From c5da5d975d90a5a52c5495e89e1d502d393c7835 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Wed, 13 Dec 2023 23:29:49 +0000 Subject: [PATCH] Bug 1866802 - Rename newtab's ASRouterAdmin to DiscoveryStreamAdmin and strip down to just Discovery Stream things. r=thecount,pdahiya Differential Revision: https://phabricator.services.mozilla.com/D194813 --- .../ASRouterAdmin/ASRouterAdmin.jsx | 1895 ----------------- .../components/ASRouterAdmin/CopyButton.jsx | 33 - .../ASRouterAdmin/ImpressionsSection.jsx | 146 -- .../content-src/components/Base/Base.jsx | 4 +- .../DiscoveryStreamAdmin.jsx | 510 +++++ .../DiscoveryStreamAdmin.scss} | 4 +- .../SimpleHashRouter.jsx | 0 .../content-src/styles/_activity-stream.scss | 2 +- .../newtab/css/activity-stream-linux.css | 120 +- .../newtab/css/activity-stream-mac.css | 120 +- .../newtab/css/activity-stream-windows.css | 120 +- .../data/content/activity-stream.bundle.js | 1326 +----------- browser/components/newtab/karma.mc.config.js | 2 +- .../unit/content-src/components/Base.test.jsx | 10 +- .../components/DiscoveryStreamAdmin.test.jsx | 302 +-- 15 files changed, 751 insertions(+), 3843 deletions(-) delete mode 100644 browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.jsx delete mode 100644 browser/components/newtab/content-src/components/ASRouterAdmin/CopyButton.jsx delete mode 100644 browser/components/newtab/content-src/components/ASRouterAdmin/ImpressionsSection.jsx create mode 100644 browser/components/newtab/content-src/components/DiscoveryStreamAdmin/DiscoveryStreamAdmin.jsx rename browser/components/newtab/content-src/components/{ASRouterAdmin/ASRouterAdmin.scss => DiscoveryStreamAdmin/DiscoveryStreamAdmin.scss} (98%) rename browser/components/newtab/content-src/components/{ASRouterAdmin => DiscoveryStreamAdmin}/SimpleHashRouter.jsx (100%) diff --git a/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.jsx b/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.jsx deleted file mode 100644 index fefe2387ba4dd..0000000000000 --- a/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.jsx +++ /dev/null @@ -1,1895 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { - actionCreators as ac, - actionTypes as at, -} from "common/Actions.sys.mjs"; -import { ASRouterUtils } from "../../asrouter/asrouter-utils"; -import { connect } from "react-redux"; -import React from "react"; -import { SimpleHashRouter } from "./SimpleHashRouter"; -import { CopyButton } from "./CopyButton"; -import { ImpressionsSection } from "./ImpressionsSection"; - -const Row = props => ( - - {props.children} - -); - -function relativeTime(timestamp) { - if (!timestamp) { - return ""; - } - const seconds = Math.floor((Date.now() - timestamp) / 1000); - const minutes = Math.floor((Date.now() - timestamp) / 60000); - if (seconds < 2) { - return "just now"; - } else if (seconds < 60) { - return `${seconds} seconds ago`; - } else if (minutes === 1) { - return "1 minute ago"; - } else if (minutes < 600) { - return `${minutes} minutes ago`; - } - return new Date(timestamp).toLocaleString(); -} - -export class ToggleStoryButton extends React.PureComponent { - constructor(props) { - super(props); - this.handleClick = this.handleClick.bind(this); - } - - handleClick() { - this.props.onClick(this.props.story); - } - - render() { - return ; - } -} - -export class ToggleMessageJSON extends React.PureComponent { - constructor(props) { - super(props); - this.handleClick = this.handleClick.bind(this); - } - - handleClick() { - this.props.toggleJSON(this.props.msgId); - } - - render() { - let iconName = this.props.isCollapsed - ? "icon icon-arrowhead-forward-small" - : "icon icon-arrowhead-down-small"; - return ( - - ); - } -} - -export class TogglePrefCheckbox extends React.PureComponent { - constructor(props) { - super(props); - this.onChange = this.onChange.bind(this); - } - - onChange(event) { - this.props.onChange(this.props.pref, event.target.checked); - } - - render() { - return ( - <> - {" "} - {this.props.pref}{" "} - - ); - } -} - -export class Personalization extends React.PureComponent { - constructor(props) { - super(props); - this.togglePersonalization = this.togglePersonalization.bind(this); - } - - togglePersonalization() { - this.props.dispatch( - ac.OnlyToMain({ - type: at.DISCOVERY_STREAM_PERSONALIZATION_TOGGLE, - }) - ); - } - - render() { - const { lastUpdated, initialized } = this.props.state.Personalization; - return ( - - - - - - - - - - - - - - - -
- - Personalization Last Updated{relativeTime(lastUpdated) || "(no data)"}Personalization Initialized{initialized ? "true" : "false"}
-
- ); - } -} - -export class DiscoveryStreamAdmin extends React.PureComponent { - constructor(props) { - super(props); - this.restorePrefDefaults = this.restorePrefDefaults.bind(this); - this.setConfigValue = this.setConfigValue.bind(this); - this.expireCache = this.expireCache.bind(this); - this.refreshCache = this.refreshCache.bind(this); - this.idleDaily = this.idleDaily.bind(this); - this.systemTick = this.systemTick.bind(this); - this.syncRemoteSettings = this.syncRemoteSettings.bind(this); - this.onStoryToggle = this.onStoryToggle.bind(this); - this.state = { - toggledStories: {}, - }; - } - - setConfigValue(name, value) { - this.props.dispatch( - ac.OnlyToMain({ - type: at.DISCOVERY_STREAM_CONFIG_SET_VALUE, - data: { name, value }, - }) - ); - } - - restorePrefDefaults(event) { - this.props.dispatch( - ac.OnlyToMain({ - type: at.DISCOVERY_STREAM_CONFIG_RESET_DEFAULTS, - }) - ); - } - - refreshCache() { - const { config } = this.props.state.DiscoveryStream; - this.props.dispatch( - ac.OnlyToMain({ - type: at.DISCOVERY_STREAM_CONFIG_CHANGE, - data: config, - }) - ); - } - - dispatchSimpleAction(type) { - this.props.dispatch( - ac.OnlyToMain({ - type, - }) - ); - } - - systemTick() { - this.dispatchSimpleAction(at.DISCOVERY_STREAM_DEV_SYSTEM_TICK); - } - - expireCache() { - this.dispatchSimpleAction(at.DISCOVERY_STREAM_DEV_EXPIRE_CACHE); - } - - idleDaily() { - this.dispatchSimpleAction(at.DISCOVERY_STREAM_DEV_IDLE_DAILY); - } - - syncRemoteSettings() { - this.dispatchSimpleAction(at.DISCOVERY_STREAM_DEV_SYNC_RS); - } - - renderComponent(width, component) { - return ( - - - - - - - - - - - {component.feed && this.renderFeed(component.feed)} - -
Type{component.type}Width{width}
- ); - } - - renderFeedData(url) { - const { feeds } = this.props.state.DiscoveryStream; - const feed = feeds.data[url].data; - return ( - -

Feed url: {url}

- - - {feed.recommendations?.map(story => this.renderStoryData(story))} - -
-
- ); - } - - renderFeedsData() { - const { feeds } = this.props.state.DiscoveryStream; - return ( - - {Object.keys(feeds.data).map(url => this.renderFeedData(url))} - - ); - } - - renderSpocs() { - const { spocs } = this.props.state.DiscoveryStream; - let spocsData = []; - if (spocs.data && spocs.data.spocs && spocs.data.spocs.items) { - spocsData = spocs.data.spocs.items || []; - } - - return ( - - - - - - - - - - - - -
spocs_endpoint{spocs.spocs_endpoint}Data last fetched{relativeTime(spocs.lastUpdated)}
-

Spoc data

- - {spocsData.map(spoc => this.renderStoryData(spoc))} -
-

Spoc frequency caps

- - - {spocs.frequency_caps.map(spoc => this.renderStoryData(spoc))} - -
-
- ); - } - - onStoryToggle(story) { - const { toggledStories } = this.state; - this.setState({ - toggledStories: { - ...toggledStories, - [story.id]: !toggledStories[story.id], - }, - }); - } - - renderStoryData(story) { - let storyData = ""; - if (this.state.toggledStories[story.id]) { - storyData = JSON.stringify(story, null, 2); - } - return ( - - - - {story.id}
-
- - - -
{storyData}
- - - ); - } - - renderFeed(feed) { - const { feeds } = this.props.state.DiscoveryStream; - if (!feed.url) { - return null; - } - return ( - - - Feed url - {feed.url} - - - Data last fetched - - {relativeTime( - feeds.data[feed.url] ? feeds.data[feed.url].lastUpdated : null - ) || "(no data)"} - - - - ); - } - - render() { - const prefToggles = "enabled collapsible".split(" "); - const { config, layout } = this.props.state.DiscoveryStream; - const personalized = - this.props.otherPrefs["discoverystream.personalization.enabled"]; - return ( -
- {" "} - -
- {" "} - {" "} - -
- - - - {prefToggles.map(pref => ( - - - - ))} - -
- -
-

Layout

- {layout.map((row, rowIndex) => ( -
- {row.components.map((component, componentIndex) => ( -
- {this.renderComponent(row.width, component)} -
- ))} -
- ))} -

Personalization

- -

Spocs

- {this.renderSpocs()} -

Feeds Data

- {this.renderFeedsData()} -
- ); - } -} - -export class ASRouterAdminInner extends React.PureComponent { - constructor(props) { - super(props); - this.handleEnabledToggle = this.handleEnabledToggle.bind(this); - this.handleUserPrefToggle = this.handleUserPrefToggle.bind(this); - this.onChangeMessageFilter = this.onChangeMessageFilter.bind(this); - this.onChangeMessageGroupsFilter = - this.onChangeMessageGroupsFilter.bind(this); - this.unblockAll = this.unblockAll.bind(this); - this.handleClearAllImpressionsByProvider = - this.handleClearAllImpressionsByProvider.bind(this); - this.handleExpressionEval = this.handleExpressionEval.bind(this); - this.onChangeTargetingParameters = - this.onChangeTargetingParameters.bind(this); - this.onChangeAttributionParameters = - this.onChangeAttributionParameters.bind(this); - this.setAttribution = this.setAttribution.bind(this); - this.onCopyTargetingParams = this.onCopyTargetingParams.bind(this); - this.onNewTargetingParams = this.onNewTargetingParams.bind(this); - this.handleOpenPB = this.handleOpenPB.bind(this); - this.selectPBMessage = this.selectPBMessage.bind(this); - this.resetPBJSON = this.resetPBJSON.bind(this); - this.resetPBMessageState = this.resetPBMessageState.bind(this); - this.toggleJSON = this.toggleJSON.bind(this); - this.toggleAllMessages = this.toggleAllMessages.bind(this); - this.resetGroups = this.resetGroups.bind(this); - this.onMessageFromParent = this.onMessageFromParent.bind(this); - this.setStateFromParent = this.setStateFromParent.bind(this); - this.setState = this.setState.bind(this); - this.state = { - messageFilter: "all", - messageGroupsFilter: "all", - collapsedMessages: [], - modifiedMessages: [], - selectedPBMessage: "", - evaluationStatus: {}, - stringTargetingParameters: null, - newStringTargetingParameters: null, - copiedToClipboard: false, - attributionParameters: { - source: "addons.mozilla.org", - medium: "referral", - campaign: "non-fx-button", - content: `rta:${btoa("uBlock0@raymondhill.net")}`, - experiment: "ua-onboarding", - variation: "chrome", - ua: "Google Chrome 123", - dltoken: "00000000-0000-0000-0000-000000000000", - }, - }; - } - - onMessageFromParent({ type, data }) { - // These only exists due to onPrefChange events in ASRouter - switch (type) { - case "UpdateAdminState": { - this.setStateFromParent(data); - break; - } - } - } - - setStateFromParent(data) { - this.setState(data); - if (!this.state.stringTargetingParameters) { - const stringTargetingParameters = {}; - for (const param of Object.keys(data.targetingParameters)) { - stringTargetingParameters[param] = JSON.stringify( - data.targetingParameters[param], - null, - 2 - ); - } - this.setState({ stringTargetingParameters }); - } - } - - componentWillMount() { - ASRouterUtils.addListener(this.onMessageFromParent); - const endpoint = ASRouterUtils.getPreviewEndpoint(); - ASRouterUtils.sendMessage({ - type: "ADMIN_CONNECT_STATE", - data: { endpoint }, - }).then(this.setStateFromParent); - } - - handleBlock(msg) { - return () => ASRouterUtils.blockById(msg.id); - } - - handleUnblock(msg) { - return () => ASRouterUtils.unblockById(msg.id); - } - - resetJSON(msg) { - // reset the displayed JSON for the given message - document.getElementById(`${msg.id}-textarea`).value = JSON.stringify( - msg, - null, - 2 - ); - // remove the message from the list of modified IDs - let index = this.state.modifiedMessages.indexOf(msg.id); - this.setState(prevState => ({ - modifiedMessages: [ - ...prevState.modifiedMessages.slice(0, index), - ...prevState.modifiedMessages.slice(index + 1), - ], - })); - } - - handleOverride(id) { - return () => - ASRouterUtils.overrideMessage(id).then(state => { - this.setStateFromParent(state); - this.props.notifyContent({ - message: state.message, - }); - }); - } - - resetPBMessageState() { - // Iterate over Private Browsing messages and block/unblock each one to clear impressions - const PBMessages = this.state.messages.filter( - message => message.template === "pb_newtab" - ); // messages from state go here - - PBMessages.forEach(message => { - if (message?.id) { - ASRouterUtils.blockById(message.id); - ASRouterUtils.unblockById(message.id); - } - }); - // Clear the selected messages & radio buttons - document.getElementById("clear radio").checked = true; - this.selectPBMessage("clear"); - } - - resetPBJSON(msg) { - // reset the displayed JSON for the given message - document.getElementById(`${msg.id}-textarea`).value = JSON.stringify( - msg, - null, - 2 - ); - } - - handleOpenPB() { - ASRouterUtils.sendMessage({ - type: "FORCE_PRIVATE_BROWSING_WINDOW", - data: { message: { content: this.state.selectedPBMessage } }, - }); - } - - expireCache() { - ASRouterUtils.sendMessage({ type: "EXPIRE_QUERY_CACHE" }); - } - - resetPref() { - ASRouterUtils.sendMessage({ type: "RESET_PROVIDER_PREF" }); - } - - resetGroups(id, value) { - ASRouterUtils.sendMessage({ - type: "RESET_GROUPS_STATE", - }).then(this.setStateFromParent); - } - - handleExpressionEval() { - const context = {}; - for (const param of Object.keys(this.state.stringTargetingParameters)) { - const value = this.state.stringTargetingParameters[param]; - context[param] = value ? JSON.parse(value) : null; - } - ASRouterUtils.sendMessage({ - type: "EVALUATE_JEXL_EXPRESSION", - data: { - expression: this.refs.expressionInput.value, - context, - }, - }).then(this.setStateFromParent); - } - - onChangeTargetingParameters(event) { - const { name } = event.target; - const { value } = event.target; - - this.setState(({ stringTargetingParameters }) => { - let targetingParametersError = null; - const updatedParameters = { ...stringTargetingParameters }; - updatedParameters[name] = value; - try { - JSON.parse(value); - } catch (e) { - console.error(`Error parsing value of parameter ${name}`); - targetingParametersError = { id: name }; - } - - return { - copiedToClipboard: false, - evaluationStatus: {}, - stringTargetingParameters: updatedParameters, - targetingParametersError, - }; - }); - } - - unblockAll() { - return ASRouterUtils.sendMessage({ - type: "UNBLOCK_ALL", - }).then(this.setStateFromParent); - } - - handleClearAllImpressionsByProvider() { - const providerId = this.state.messageFilter; - if (!providerId) { - return; - } - const userPrefInfo = this.state.userPrefs; - - const isUserEnabled = - providerId in userPrefInfo ? userPrefInfo[providerId] : true; - - ASRouterUtils.sendMessage({ - type: "DISABLE_PROVIDER", - data: providerId, - }); - if (!isUserEnabled) { - ASRouterUtils.sendMessage({ - type: "SET_PROVIDER_USER_PREF", - data: { id: providerId, value: true }, - }); - } - ASRouterUtils.sendMessage({ - type: "ENABLE_PROVIDER", - data: providerId, - }); - } - - handleEnabledToggle(event) { - const provider = this.state.providerPrefs.find( - p => p.id === event.target.dataset.provider - ); - const userPrefInfo = this.state.userPrefs; - - const isUserEnabled = - provider.id in userPrefInfo ? userPrefInfo[provider.id] : true; - const isSystemEnabled = provider.enabled; - const isEnabling = event.target.checked; - - if (isEnabling) { - if (!isUserEnabled) { - ASRouterUtils.sendMessage({ - type: "SET_PROVIDER_USER_PREF", - data: { id: provider.id, value: true }, - }); - } - if (!isSystemEnabled) { - ASRouterUtils.sendMessage({ - type: "ENABLE_PROVIDER", - data: provider.id, - }); - } - } else { - ASRouterUtils.sendMessage({ - type: "DISABLE_PROVIDER", - data: provider.id, - }); - } - - this.setState({ messageFilter: "all" }); - } - - handleUserPrefToggle(event) { - const action = { - type: "SET_PROVIDER_USER_PREF", - data: { id: event.target.dataset.provider, value: event.target.checked }, - }; - ASRouterUtils.sendMessage(action); - this.setState({ messageFilter: "all" }); - } - - onChangeMessageFilter(event) { - this.setState({ messageFilter: event.target.value }); - } - - onChangeMessageGroupsFilter(event) { - this.setState({ messageGroupsFilter: event.target.value }); - } - - // Simulate a copy event that sets to clipboard all targeting paramters and values - onCopyTargetingParams(event) { - const stringTargetingParameters = { - ...this.state.stringTargetingParameters, - }; - for (const key of Object.keys(stringTargetingParameters)) { - // If the value is not set the parameter will be lost when we stringify - if (stringTargetingParameters[key] === undefined) { - stringTargetingParameters[key] = null; - } - } - const setClipboardData = e => { - e.preventDefault(); - e.clipboardData.setData( - "text", - JSON.stringify(stringTargetingParameters, null, 2) - ); - document.removeEventListener("copy", setClipboardData); - this.setState({ copiedToClipboard: true }); - }; - - document.addEventListener("copy", setClipboardData); - - document.execCommand("copy"); - } - - onNewTargetingParams(event) { - this.setState({ newStringTargetingParameters: event.target.value }); - event.target.classList.remove("errorState"); - this.refs.targetingParamsEval.innerText = ""; - - try { - const stringTargetingParameters = JSON.parse(event.target.value); - this.setState({ stringTargetingParameters }); - } catch (e) { - event.target.classList.add("errorState"); - this.refs.targetingParamsEval.innerText = e.message; - } - } - - toggleJSON(msgId) { - if (this.state.collapsedMessages.includes(msgId)) { - let index = this.state.collapsedMessages.indexOf(msgId); - this.setState(prevState => ({ - collapsedMessages: [ - ...prevState.collapsedMessages.slice(0, index), - ...prevState.collapsedMessages.slice(index + 1), - ], - })); - } else { - this.setState(prevState => ({ - collapsedMessages: prevState.collapsedMessages.concat(msgId), - })); - } - } - - handleChange(msgId) { - if (!this.state.modifiedMessages.includes(msgId)) { - this.setState(prevState => ({ - modifiedMessages: prevState.modifiedMessages.concat(msgId), - })); - } - } - - renderMessageItem(msg) { - const isBlockedByGroup = this.state.groups - .filter(group => msg.groups.includes(group.id)) - .some(group => !group.enabled); - const msgProvider = - this.state.providers.find(provider => provider.id === msg.provider) || {}; - const isProviderExcluded = - msgProvider.exclude && msgProvider.exclude.includes(msg.id); - const isMessageBlocked = - this.state.messageBlockList.includes(msg.id) || - this.state.messageBlockList.includes(msg.campaign); - const isBlocked = - isMessageBlocked || isBlockedByGroup || isProviderExcluded; - const impressions = this.state.messageImpressions[msg.id] - ? this.state.messageImpressions[msg.id].length - : 0; - const isCollapsed = this.state.collapsedMessages.includes(msg.id); - const isModified = this.state.modifiedMessages.includes(msg.id); - const aboutMessagePreviewSupported = [ - "infobar", - "spotlight", - "cfr_doorhanger", - ].includes(msg.template); - - let itemClassName = "message-item"; - if (isBlocked) { - itemClassName += " blocked"; - } - - return ( - - - - {msg.id}
-
- - - - - - - { - // eslint-disable-next-line no-nested-ternary - isBlocked ? null : isModified ? ( - - ) : ( - - ) - } - {isBlocked ? null : ( - - )} - {aboutMessagePreviewSupported ? ( - - `about:messagepreview?json=${encodeURIComponent(btoa(text))}` - } - label="Share" - copiedLabel="Copied!" - inputSelector={`#${msg.id}-textarea`} - className={"button share"} - /> - ) : null} -
({impressions} impressions) - - - {isBlocked && ( - - Block reason: - {isBlockedByGroup && " Blocked by group"} - {isProviderExcluded && " Excluded by provider"} - {isMessageBlocked && " Message blocked"} - - )} - -
-              
-            
- - - - ); - } - - selectPBMessage(msgId) { - if (msgId === "clear") { - this.setState({ - selectedPBMessage: "", - }); - } else { - let selected = document.getElementById(`${msgId} radio`); - let msg = JSON.parse(document.getElementById(`${msgId}-textarea`).value); - - if (selected.checked) { - this.setState({ - selectedPBMessage: msg?.content, - }); - } else { - this.setState({ - selectedPBMessage: "", - }); - } - } - } - - modifyJson(content) { - const message = JSON.parse( - document.getElementById(`${content.id}-textarea`).value - ); - return ASRouterUtils.modifyMessageJson(message).then(state => { - this.setStateFromParent(state); - this.props.notifyContent({ - message: state.message, - }); - }); - } - - renderPBMessageItem(msg) { - const isBlocked = - this.state.messageBlockList.includes(msg.id) || - this.state.messageBlockList.includes(msg.campaign); - const impressions = this.state.messageImpressions[msg.id] - ? this.state.messageImpressions[msg.id].length - : 0; - - const isCollapsed = this.state.collapsedMessages.includes(msg.id); - - let itemClassName = "message-item"; - if (isBlocked) { - itemClassName += " blocked"; - } - - return ( - - - - {msg.id}
-
({impressions} impressions) -
- - - - - - this.selectPBMessage(msg.id)} - disabled={isBlocked} - /> - - - - -
-            
-          
- - - ); - } - - toggleAllMessages(messagesToShow) { - if (this.state.collapsedMessages.length) { - this.setState({ - collapsedMessages: [], - }); - } else { - Array.prototype.forEach.call(messagesToShow, msg => { - this.setState(prevState => ({ - collapsedMessages: prevState.collapsedMessages.concat(msg.id), - })); - }); - } - } - - renderMessages() { - if (!this.state.messages) { - return null; - } - const messagesToShow = - this.state.messageFilter === "all" - ? this.state.messages - : this.state.messages.filter( - message => - message.provider === this.state.messageFilter && - message.template !== "pb_newtab" - ); - - return ( -
- -

- {" "} - - To modify a message, change the JSON and click 'Modify' to see your - changes. Click 'Reset' to restore the JSON to the original. Click - 'Share' to copy a link to the clipboard that can be used to preview - the message by opening the link in Nightly/local builds. - -

- - - {messagesToShow.map(msg => this.renderMessageItem(msg))} - -
-
- ); - } - - renderMessagesByGroup() { - if (!this.state.messages) { - return null; - } - const messagesToShow = - this.state.messageGroupsFilter === "all" - ? this.state.messages.filter(m => m.groups.length) - : this.state.messages.filter(message => - message.groups.includes(this.state.messageGroupsFilter) - ); - - return ( - - {messagesToShow.map(msg => this.renderMessageItem(msg))} -
- ); - } - - renderPBMessages() { - if (!this.state.messages) { - return null; - } - const messagesToShow = this.state.messages.filter( - message => message.template === "pb_newtab" - ); - return ( - - - {messagesToShow.map(msg => this.renderPBMessageItem(msg))} - -
- ); - } - - renderMessageFilter() { - if (!this.state.providers) { - return null; - } - - return ( -

- - Show messages from{" "} - - {this.state.messageFilter !== "all" && - !this.state.messageFilter.includes("_local_testing") ? ( - - ) : null} -

- ); - } - - renderMessageGroupsFilter() { - if (!this.state.groups) { - return null; - } - - return ( -

- Show messages from {/* eslint-disable-next-line jsx-a11y/no-onchange */} - -

- ); - } - - renderTableHead() { - return ( - - - - Provider ID - Source - Cohort - Last Updated - - - ); - } - - renderProviders() { - const providersConfig = this.state.providerPrefs; - const providerInfo = this.state.providers; - const userPrefInfo = this.state.userPrefs; - - return ( - - {this.renderTableHead()} - - {providersConfig.map((provider, i) => { - const isTestProvider = provider.id.includes("_local_testing"); - const info = providerInfo.find(p => p.id === provider.id) || {}; - const isUserEnabled = - provider.id in userPrefInfo ? userPrefInfo[provider.id] : true; - const isSystemEnabled = isTestProvider || provider.enabled; - - let label = "local"; - if (provider.type === "remote") { - label = ( - - endpoint ( - - {info.url} - - ) - - ); - } else if (provider.type === "remote-settings") { - label = `remote settings (${provider.collection})`; - } else if (provider.type === "remote-experiments") { - label = ( - - remote settings ( - - nimbus-desktop-experiments - - ) - - ); - } - - let reasonsDisabled = []; - if (!isSystemEnabled) { - reasonsDisabled.push("system pref"); - } - if (!isUserEnabled) { - reasonsDisabled.push("user pref"); - } - if (reasonsDisabled.length) { - label = `disabled via ${reasonsDisabled.join(", ")}`; - } - - return ( - - - - - - - - ); - })} - -
- {isTestProvider ? ( - - ) : ( - - )} - {provider.id} - - {label} - - {provider.cohort} - {info.lastUpdated - ? new Date(info.lastUpdated).toLocaleString() - : ""} -
- ); - } - - renderTargetingParameters() { - // There was no error and the result is truthy - const success = - this.state.evaluationStatus.success && - !!this.state.evaluationStatus.result; - const result = - JSON.stringify(this.state.evaluationStatus.result, null, 2) || - "(Empty result)"; - - return ( - - - - - - -
-

Evaluate JEXL expression

-
-

-