mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
Bug 1866802 - Move ASRouterAdmin tool to about:asrouter and its own component folder. r=pdahiya,Gijs,desktop-theme-reviewers,dao
This tries to maintain stylistic continuity, while also trying to decouple from newtab as much as possible. This is a first foray, and future patches will further this decoupling. This also modifies about:asrouter to show an error message if the ASRouter devtools pref is not set to true. Differential Revision: https://phabricator.services.mozilla.com/D194811
This commit is contained in:
parent
19fe553001
commit
9415a9f13d
@ -233,6 +233,7 @@ module.exports = {
|
||||
"browser/components/Browser*",
|
||||
"browser/components/aboutlogins/**",
|
||||
"browser/components/aboutwelcome/**",
|
||||
"browser/components/asrouter/**",
|
||||
"browser/components/attribution/**",
|
||||
"browser/components/customizableui/**",
|
||||
"browser/components/downloads/**",
|
||||
@ -498,6 +499,7 @@ module.exports = {
|
||||
extends: ["plugin:react-hooks/recommended"],
|
||||
files: [
|
||||
"browser/components/aboutwelcome/**",
|
||||
"browser/components/asrouter/**",
|
||||
"browser/components/newtab/**",
|
||||
"browser/components/pocket/**",
|
||||
"devtools/**",
|
||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -56,12 +56,20 @@ security/manager/.nss.checkout
|
||||
# gecko.log is generated by various test harnesses
|
||||
/gecko.log
|
||||
|
||||
# Ignore all node_modules directories
|
||||
node_modules/
|
||||
# ...but allow ones under third_party
|
||||
!/third_party/**/node_modules/
|
||||
|
||||
# Ignore newtab component build assets
|
||||
browser/components/newtab/logs/
|
||||
|
||||
# Ignore about:welcome component build assets
|
||||
browser/components/aboutwelcome/logs/
|
||||
|
||||
# Ignore ASRouter component build assets
|
||||
browser/components/asrouter/logs/
|
||||
|
||||
# Ignore ASRouter generated test files
|
||||
browser/components/newtab/content-src/asrouter/schemas/corpus/CFRMessageProvider.messages.json
|
||||
browser/components/newtab/content-src/asrouter/schemas/corpus/OnboardingMessageProvider.messages.json
|
||||
|
@ -60,6 +60,9 @@ compile_commands\.json
|
||||
# Ignore about:welcome build assets
|
||||
^browser/components/aboutwelcome/logs/
|
||||
|
||||
# Ignore ASRouter component build assets
|
||||
^browser/components/asrouter/logs/
|
||||
|
||||
# Ignore ASRouter generated test files
|
||||
^browser/components/newtab/content-src/asrouter/schemas/corpus/CFRMessageProvider.messages.json
|
||||
^browser/components/newtab/content-src/asrouter/schemas/corpus/OnboardingMessageProvider.messages.json
|
||||
@ -198,6 +201,7 @@ _OPT\.OBJ/
|
||||
^node_modules/
|
||||
^tools/browsertime/node_modules/
|
||||
^tools/lint/eslint/eslint-plugin-mozilla/node_modules/
|
||||
^browser/components/asrouter/node_modules/
|
||||
^browser/components/newtab/node_modules/
|
||||
^browser/components/aboutwelcome/node_modules/
|
||||
^tools/esmify/node_modules/
|
||||
|
@ -1449,6 +1449,9 @@ xpcom/io/crc32c.c
|
||||
|
||||
.gradle/
|
||||
browser/components/aboutwelcome/content/aboutwelcome.bundle.js
|
||||
browser/components/asrouter/node_modules/
|
||||
browser/components/asrouter/content/asrouter-admin.bundle.js
|
||||
browser/components/asrouter/logs/
|
||||
browser/components/newtab/content-src/asrouter/schemas/BackgroundTaskMessagingExperiment.schema.json
|
||||
browser/components/newtab/content-src/asrouter/schemas/MessagingExperiment.schema.json
|
||||
browser/components/newtab/logs/
|
||||
|
@ -26,6 +26,7 @@ obj*/
|
||||
browser/components/pocket/content/panels/css/main.compiled.css
|
||||
browser/components/newtab/**/*.css
|
||||
browser/components/aboutwelcome/**/*.css
|
||||
browser/components/asrouter/**/*.css
|
||||
|
||||
# Note that the debugger has its own stylelint setup, but that currently
|
||||
# produces errors. Bug 1831302 tracks making this better
|
||||
|
@ -260,6 +260,7 @@ module.exports = {
|
||||
{
|
||||
files: [
|
||||
"browser/components/aboutwelcome/**",
|
||||
"browser/components/asrouter/**",
|
||||
"browser/components/newtab/**",
|
||||
],
|
||||
customSyntax: "postcss-scss",
|
||||
|
@ -581,6 +581,7 @@ let JSWINDOWACTORS = {
|
||||
includeChrome: true,
|
||||
allFrames: true,
|
||||
matches: [
|
||||
"about:asrouter",
|
||||
"about:home",
|
||||
"about:newtab",
|
||||
"about:welcome",
|
||||
@ -796,6 +797,7 @@ let JSWINDOWACTORS = {
|
||||
},
|
||||
},
|
||||
matches: [
|
||||
"about:asrouter*",
|
||||
"about:home*",
|
||||
"about:newtab*",
|
||||
"about:welcome*",
|
||||
|
@ -44,6 +44,11 @@ struct RedirEntry {
|
||||
browser/components/about/components.conf
|
||||
*/
|
||||
static const RedirEntry kRedirMap[] = {
|
||||
{"asrouter", "chrome://browser/content/asrouter/asrouter-admin.html",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
|
||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT},
|
||||
{"blocked", "chrome://browser/content/blockedSite.xhtml",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
|
||||
|
@ -5,6 +5,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
pages = [
|
||||
'asrouter',
|
||||
'blocked',
|
||||
'certerror',
|
||||
'downloads',
|
||||
|
175
browser/components/asrouter/.eslintrc.js
Normal file
175
browser/components/asrouter/.eslintrc.js
Normal file
@ -0,0 +1,175 @@
|
||||
/* 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/. */
|
||||
|
||||
module.exports = {
|
||||
// When adding items to this file please check for effects on sub-directories.
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
plugins: ["import", "react", "jsx-a11y"],
|
||||
settings: {
|
||||
react: {
|
||||
version: "16.2.0",
|
||||
},
|
||||
},
|
||||
extends: ["plugin:jsx-a11y/recommended"],
|
||||
overrides: [
|
||||
{
|
||||
// Only mark the files as modules which are actually modules.
|
||||
// TODO: Add "tests/unit/**" to this list once we get our tests built.
|
||||
files: ["content-src/**"],
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
{
|
||||
// TODO: Add ./*.js and tests/unit/** to this list if necessary
|
||||
files: ["./*.js", "content-src/**"],
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
},
|
||||
/* TODO: Turn this rule on when I move the tests over.
|
||||
{
|
||||
// Use a configuration that's appropriate for modules, workers and
|
||||
// non-production files.
|
||||
files: ["modules/*.jsm", "tests/**"],
|
||||
rules: {
|
||||
"no-implicit-globals": "off",
|
||||
},
|
||||
},
|
||||
*/
|
||||
{
|
||||
// TODO: Add "tests/unit/**" to this list once we get our tests built.
|
||||
files: ["content-src/**"],
|
||||
rules: {
|
||||
// Disallow commonjs in these directories.
|
||||
"import/no-commonjs": 2,
|
||||
// Allow JSX with arrow functions.
|
||||
"react/jsx-no-bind": 0,
|
||||
},
|
||||
},
|
||||
/* TODO: Turn this rule on when I move the tests over.
|
||||
{
|
||||
// These tests simulate the browser environment.
|
||||
files: "tests/unit/**",
|
||||
env: {
|
||||
browser: true,
|
||||
mocha: true,
|
||||
},
|
||||
globals: {
|
||||
assert: true,
|
||||
chai: true,
|
||||
sinon: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: "tests/**",
|
||||
rules: {
|
||||
"func-name-matching": 0,
|
||||
"lines-between-class-members": 0,
|
||||
"require-await": 0,
|
||||
},
|
||||
},*/
|
||||
],
|
||||
rules: {
|
||||
"fetch-options/no-fetch-credentials": "error",
|
||||
|
||||
"react/jsx-boolean-value": ["error", "always"],
|
||||
"react/jsx-key": "error",
|
||||
"react/jsx-no-bind": "error",
|
||||
"react/jsx-no-comment-textnodes": "error",
|
||||
"react/jsx-no-duplicate-props": "error",
|
||||
"react/jsx-no-target-blank": "error",
|
||||
"react/jsx-no-undef": "error",
|
||||
"react/jsx-pascal-case": "error",
|
||||
"react/jsx-uses-react": "error",
|
||||
"react/jsx-uses-vars": "error",
|
||||
"react/no-access-state-in-setstate": "error",
|
||||
"react/no-danger": "error",
|
||||
"react/no-deprecated": "error",
|
||||
"react/no-did-mount-set-state": "error",
|
||||
"react/no-did-update-set-state": "error",
|
||||
"react/no-direct-mutation-state": "error",
|
||||
"react/no-is-mounted": "error",
|
||||
"react/no-unknown-property": "error",
|
||||
"react/require-render-return": "error",
|
||||
|
||||
"accessor-pairs": ["error", { setWithoutGet: true, getWithoutSet: false }],
|
||||
"array-callback-return": "error",
|
||||
"block-scoped-var": "error",
|
||||
"consistent-this": ["error", "use-bind"],
|
||||
eqeqeq: "error",
|
||||
"for-direction": "error",
|
||||
"func-name-matching": "error",
|
||||
"getter-return": "error",
|
||||
"guard-for-in": "error",
|
||||
"handle-callback-err": "error",
|
||||
"lines-between-class-members": "error",
|
||||
"max-depth": ["error", 4],
|
||||
"max-nested-callbacks": ["error", 4],
|
||||
"max-params": ["error", 6],
|
||||
"max-statements": ["error", 50],
|
||||
"max-statements-per-line": ["error", { max: 2 }],
|
||||
"new-cap": ["error", { newIsCap: true, capIsNew: false }],
|
||||
"no-alert": "error",
|
||||
"no-buffer-constructor": "error",
|
||||
"no-console": ["error", { allow: ["error"] }],
|
||||
"no-div-regex": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-eq-null": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-extra-label": "error",
|
||||
"no-implicit-coercion": ["error", { allow: ["!!"] }],
|
||||
"no-implicit-globals": "error",
|
||||
"no-loop-func": "error",
|
||||
"no-mixed-requires": "error",
|
||||
"no-multi-assign": "error",
|
||||
"no-multi-str": "error",
|
||||
"no-new": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-require": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-param-reassign": "error",
|
||||
"no-path-concat": "error",
|
||||
"no-process-exit": "error",
|
||||
"no-proto": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
"no-return-assign": ["error", "except-parens"],
|
||||
"no-script-url": "error",
|
||||
"no-shadow": "error",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-undef-init": "error",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-use-before-define": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"no-useless-rename": "error",
|
||||
"no-var": "error",
|
||||
"no-void": ["error", { allowAsStatement: true }],
|
||||
"one-var": ["error", "never"],
|
||||
"operator-assignment": ["error", "always"],
|
||||
"prefer-destructuring": [
|
||||
"error",
|
||||
{
|
||||
AssignmentExpression: { array: true },
|
||||
VariableDeclarator: { array: true, object: true },
|
||||
},
|
||||
],
|
||||
"prefer-numeric-literals": "error",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"prefer-rest-params": "error",
|
||||
"prefer-spread": "error",
|
||||
"prefer-template": "error",
|
||||
radix: ["error", "always"],
|
||||
"require-await": "error",
|
||||
"sort-vars": "error",
|
||||
"symbol-description": "error",
|
||||
"vars-on-top": "error",
|
||||
yoda: ["error", "never"],
|
||||
},
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,353 @@
|
||||
/* 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/. */
|
||||
|
||||
/* stylelint-disable max-nesting-depth */
|
||||
|
||||
@import '../../../../newtab/content-src/styles/variables';
|
||||
@import '../../../../newtab/content-src/styles/theme';
|
||||
@import '../../../../newtab/content-src/styles/icons';
|
||||
@import '../../../../newtab/content-src/asrouter/components/Button/Button';
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Ubuntu, 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
|
||||
/**
|
||||
* These styles are copied verbatim from _activity-stream.scss in order to maintain
|
||||
* a continuity of styling while also decoupling from the newtab code. This should
|
||||
* be removed when about:asrouter starts using the default in-content style sheets.
|
||||
*/
|
||||
.button,
|
||||
.actions button {
|
||||
background-color: var(--newtab-button-secondary-color);
|
||||
border: $border-primary;
|
||||
border-radius: 4px;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
margin-bottom: 15px;
|
||||
padding: 10px 30px;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover:not(.dismiss),
|
||||
&:focus:not(.dismiss) {
|
||||
box-shadow: $shadow-primary;
|
||||
transition: box-shadow 150ms;
|
||||
}
|
||||
|
||||
&.dismiss {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
// Blue button
|
||||
&.primary,
|
||||
&.done {
|
||||
background-color: var(--newtab-primary-action-background);
|
||||
border: solid 1px var(--newtab-primary-action-background);
|
||||
color: var(--newtab-primary-element-text-color);
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.asrouter-admin {
|
||||
max-width: 1300px;
|
||||
$border-color: var(--newtab-border-color);
|
||||
$monospace: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Mono', 'Droid Sans Mono',
|
||||
'Source Code Pro', monospace;
|
||||
$sidebar-width: 240px;
|
||||
|
||||
font-size: 14px;
|
||||
padding-inline-start: $sidebar-width;
|
||||
color: var(--newtab-text-primary-color);
|
||||
|
||||
&.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
inset-inline-start: 0;
|
||||
position: fixed;
|
||||
width: $sidebar-width;
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
li a {
|
||||
padding: 10px 34px;
|
||||
display: block;
|
||||
color: var(--lwt-sidebar-text-color);
|
||||
|
||||
&:hover {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 200;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
h2 .button,
|
||||
p .button {
|
||||
font-size: 14px;
|
||||
padding: 6px 12px;
|
||||
margin-inline-start: 5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.general-textarea {
|
||||
direction: ltr;
|
||||
width: 740px;
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
resize: none;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.wnp-textarea {
|
||||
direction: ltr;
|
||||
width: 740px;
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
resize: none;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.json-button {
|
||||
display: inline-flex;
|
||||
font-size: 10px;
|
||||
padding: 4px 10px;
|
||||
margin-bottom: 6px;
|
||||
margin-inline-end: 4px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--newtab-element-hover-color);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
|
||||
&.minimal-table {
|
||||
border-collapse: collapse;
|
||||
border: 1px solid $border-color;
|
||||
|
||||
td {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
width: 1%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
td:not(:first-child) {
|
||||
font-family: $monospace;
|
||||
}
|
||||
}
|
||||
|
||||
&.errorReporting {
|
||||
tr {
|
||||
border: 1px solid var(--newtab-background-color-secondary);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 4px;
|
||||
|
||||
&[rowspan] {
|
||||
border: 1px solid var(--newtab-background-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sourceLabel {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
|
||||
&.isDisabled {
|
||||
background: $email-input-invalid;
|
||||
color: var(--newtab-status-error);
|
||||
}
|
||||
}
|
||||
|
||||
.message-item {
|
||||
&:first-child td {
|
||||
border-top: 1px solid $border-color;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
|
||||
&.min {
|
||||
width: 1%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.message-summary {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
&.button-column {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-inline-start: 1px solid $border-color;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-inline-end: 1px solid $border-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.blocked {
|
||||
.message-id,
|
||||
.message-summary {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.message-id {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.message-id {
|
||||
font-family: $monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.providerUrl {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
max-width: 750px;
|
||||
overflow: auto;
|
||||
font-family: $monospace;
|
||||
}
|
||||
|
||||
.errorState {
|
||||
border: $input-error-border;
|
||||
}
|
||||
|
||||
.helpLink {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
background: $black-10;
|
||||
border-radius: 3px;
|
||||
align-items: center;
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.icon {
|
||||
min-width: 18px;
|
||||
min-height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-component {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.modalOverlayInner {
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
.clearButton {
|
||||
border: 0;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
|
||||
&:hover {
|
||||
background: var(--newtab-element-hover-color);
|
||||
}
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-table;
|
||||
cursor: pointer;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.button {
|
||||
&:disabled,
|
||||
&:disabled:active {
|
||||
opacity: 0.5;
|
||||
cursor: unset;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.impressions-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
|
||||
.impressions-item {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
padding: 8px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 5px;
|
||||
|
||||
.impressions-inner-box {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.impressions-category {
|
||||
font-size: 1.15em;
|
||||
white-space: nowrap;
|
||||
flex-grow: 0.1;
|
||||
}
|
||||
|
||||
.impressions-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.impressions-editor {
|
||||
display: flex;
|
||||
flex-grow: 1.5;
|
||||
|
||||
.general-textarea {
|
||||
width: auto;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/* 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 React, { useState, useRef, useCallback } from "react";
|
||||
|
||||
export const CopyButton = ({
|
||||
className,
|
||||
label,
|
||||
copiedLabel,
|
||||
inputSelector,
|
||||
transformer,
|
||||
...props
|
||||
}) => {
|
||||
const [copied, setCopied] = useState(false);
|
||||
const timeout = useRef(null);
|
||||
const onClick = useCallback(() => {
|
||||
let text = document.querySelector(inputSelector).value;
|
||||
if (transformer) {
|
||||
text = transformer(text);
|
||||
}
|
||||
navigator.clipboard.writeText(text);
|
||||
|
||||
clearTimeout(timeout.current);
|
||||
setCopied(true);
|
||||
timeout.current = setTimeout(() => setCopied(false), 1500);
|
||||
}, [inputSelector, transformer]);
|
||||
return (
|
||||
<button className={className} onClick={e => onClick()} {...props}>
|
||||
{(copied && copiedLabel) || label}
|
||||
</button>
|
||||
);
|
||||
};
|
@ -0,0 +1,146 @@
|
||||
/* 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 { ASRouterUtils } from "newtab/content-src/asrouter/asrouter-utils";
|
||||
import React, {
|
||||
useState,
|
||||
useMemo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "react";
|
||||
|
||||
const stringify = json => JSON.stringify(json, null, 2);
|
||||
|
||||
export const ImpressionsSection = ({
|
||||
messageImpressions,
|
||||
groupImpressions,
|
||||
screenImpressions,
|
||||
}) => {
|
||||
const handleSaveMessageImpressions = useCallback(newImpressions => {
|
||||
ASRouterUtils.editState("messageImpressions", newImpressions);
|
||||
}, []);
|
||||
const handleSaveGroupImpressions = useCallback(newImpressions => {
|
||||
ASRouterUtils.editState("groupImpressions", newImpressions);
|
||||
}, []);
|
||||
const handleSaveScreenImpressions = useCallback(newImpressions => {
|
||||
ASRouterUtils.editState("screenImpressions", newImpressions);
|
||||
}, []);
|
||||
|
||||
const handleResetMessageImpressions = useCallback(() => {
|
||||
ASRouterUtils.sendMessage({ type: "RESET_MESSAGE_STATE" });
|
||||
}, []);
|
||||
const handleResetGroupImpressions = useCallback(() => {
|
||||
ASRouterUtils.sendMessage({ type: "RESET_GROUPS_STATE" });
|
||||
}, []);
|
||||
const handleResetScreenImpressions = useCallback(() => {
|
||||
ASRouterUtils.sendMessage({ type: "RESET_SCREEN_IMPRESSIONS" });
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="impressions-section">
|
||||
<ImpressionsItem
|
||||
impressions={messageImpressions}
|
||||
label="Message Impressions"
|
||||
description="Message impressions are stored in an object, where each key is a message ID and each value is an array of timestamps. They are cleaned up when a message with that ID stops existing in ASRouter state (such as at the end of an experiment)."
|
||||
onSave={handleSaveMessageImpressions}
|
||||
onReset={handleResetMessageImpressions}
|
||||
/>
|
||||
<ImpressionsItem
|
||||
impressions={groupImpressions}
|
||||
label="Group Impressions"
|
||||
description="Group impressions are stored in an object, where each key is a group ID and each value is an array of timestamps. They are never cleaned up."
|
||||
onSave={handleSaveGroupImpressions}
|
||||
onReset={handleResetGroupImpressions}
|
||||
/>
|
||||
<ImpressionsItem
|
||||
impressions={screenImpressions}
|
||||
label="Screen Impressions"
|
||||
description="Screen impressions are stored in an object, where each key is a screen ID and each value is the most recent timestamp that screen was shown. They are never cleaned up."
|
||||
onSave={handleSaveScreenImpressions}
|
||||
onReset={handleResetScreenImpressions}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ImpressionsItem = ({
|
||||
impressions,
|
||||
label,
|
||||
description,
|
||||
validator,
|
||||
onSave,
|
||||
onReset,
|
||||
}) => {
|
||||
const [json, setJson] = useState(stringify(impressions));
|
||||
|
||||
const modified = useRef(false);
|
||||
|
||||
const isValidJson = useCallback(
|
||||
text => {
|
||||
try {
|
||||
JSON.parse(text);
|
||||
return validator ? validator(text) : true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[validator]
|
||||
);
|
||||
|
||||
const jsonIsInvalid = useMemo(() => !isValidJson(json), [json, isValidJson]);
|
||||
|
||||
const handleChange = useCallback(e => {
|
||||
setJson(e.target.value);
|
||||
modified.current = true;
|
||||
}, []);
|
||||
const handleSave = useCallback(() => {
|
||||
if (jsonIsInvalid) {
|
||||
return;
|
||||
}
|
||||
const newImpressions = JSON.parse(json);
|
||||
modified.current = false;
|
||||
onSave(newImpressions);
|
||||
}, [json, jsonIsInvalid, onSave]);
|
||||
const handleReset = useCallback(() => {
|
||||
modified.current = false;
|
||||
onReset();
|
||||
}, [onReset]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!modified.current) {
|
||||
setJson(stringify(impressions));
|
||||
}
|
||||
}, [impressions]);
|
||||
|
||||
return (
|
||||
<div className="impressions-item">
|
||||
<span className="impressions-category">{label}</span>
|
||||
{description ? (
|
||||
<p className="impressions-description">{description}</p>
|
||||
) : null}
|
||||
<div className="impressions-inner-box">
|
||||
<div className="impressions-buttons">
|
||||
<button
|
||||
className="button primary"
|
||||
disabled={jsonIsInvalid}
|
||||
onClick={handleSave}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<button className="button reset" onClick={handleReset}>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
<div className="impressions-editor">
|
||||
<textarea
|
||||
className="general-textarea"
|
||||
value={json}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,35 @@
|
||||
/* 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 React from "react";
|
||||
|
||||
export class SimpleHashRouter extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onHashChange = this.onHashChange.bind(this);
|
||||
this.state = { hash: global.location.hash };
|
||||
}
|
||||
|
||||
onHashChange() {
|
||||
this.setState({ hash: global.location.hash });
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
global.addEventListener("hashchange", this.onHashChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
global.removeEventListener("hashchange", this.onHashChange);
|
||||
}
|
||||
|
||||
render() {
|
||||
const [, ...routes] = this.state.hash.split("-");
|
||||
return React.cloneElement(this.props.children, {
|
||||
location: {
|
||||
hash: this.state.hash,
|
||||
routes,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
1946
browser/components/asrouter/content/asrouter-admin.bundle.js
Normal file
1946
browser/components/asrouter/content/asrouter-admin.bundle.js
Normal file
File diff suppressed because it is too large
Load Diff
38
browser/components/asrouter/content/asrouter-admin.html
Normal file
38
browser/components/asrouter/content/asrouter-admin.html
Normal file
@ -0,0 +1,38 @@
|
||||
<!-- 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/. -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; object-src 'none'; script-src resource: chrome:;"
|
||||
/>
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<title>ASRouter Admin</title>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
href="chrome://branding/content/icon32.png"
|
||||
/>
|
||||
<link rel="localization" href="branding/brand.ftl" />
|
||||
<link rel="localization" href="toolkit/branding/brandings.ftl" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="chrome://browser/content/asrouter/components/ASRouterAdmin/ASRouterAdmin.css"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="chrome://browser/content/contentTheme.js"></script>
|
||||
<script src="resource://activity-stream/vendor/react.js"></script>
|
||||
<script src="resource://activity-stream/vendor/react-dom.js"></script>
|
||||
<script src="resource://activity-stream/vendor/prop-types.js"></script>
|
||||
<script src="chrome://browser/content/asrouter/asrouter-admin.bundle.js"></script>
|
||||
|
||||
<!-- The render.js script is the main entrypoint for the page. -->
|
||||
<script src="chrome://browser/content/asrouter/render.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,546 @@
|
||||
/* 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/. */
|
||||
/* stylelint-disable max-nesting-depth */
|
||||
:root {
|
||||
--newtab-background-color: #F9F9FB;
|
||||
--newtab-background-color-secondary: #FFF;
|
||||
--newtab-text-primary-color: #15141a;
|
||||
--newtab-primary-action-background: #0061e0;
|
||||
--newtab-primary-action-background-pocket: #008078;
|
||||
--newtab-text-secondary-color: color-mix(in srgb, var(--newtab-text-primary-color) 70%, transparent);
|
||||
--newtab-element-hover-color: color-mix(in srgb, var(--newtab-background-color) 90%, #000);
|
||||
--newtab-element-active-color: color-mix(in srgb, var(--newtab-background-color) 80%, #000);
|
||||
--newtab-element-secondary-color: color-mix(in srgb, currentColor 5%, transparent);
|
||||
--newtab-element-secondary-hover-color: color-mix(in srgb, currentColor 12%, transparent);
|
||||
--newtab-element-secondary-active-color: color-mix(in srgb, currentColor 25%, transparent);
|
||||
--newtab-primary-element-hover-color: color-mix(in srgb, var(--newtab-primary-action-background) 90%, #000);
|
||||
--newtab-primary-element-hover-pocket-color: color-mix(in srgb, var(--newtab-primary-action-background-pocket) 90%, #000);
|
||||
--newtab-primary-element-active-color: color-mix(in srgb, var(--newtab-primary-action-background) 80%, #000);
|
||||
--newtab-primary-element-text-color: #FFF;
|
||||
--newtab-primary-action-background-dimmed: color-mix(in srgb, var(--newtab-primary-action-background) 25%, transparent);
|
||||
--newtab-primary-action-background-pocket-dimmed: color-mix(in srgb, var(--newtab-primary-action-background-pocket) 25%, transparent);
|
||||
--newtab-border-color: color-mix(in srgb, var(--newtab-background-color) 75%, #000);
|
||||
--newtab-wordmark-color: #20123A;
|
||||
--newtab-status-success: #058B00;
|
||||
--newtab-status-error: #D70022;
|
||||
--newtab-inner-box-shadow-color: rgba(0, 0, 0, 0.1);
|
||||
--newtab-overlay-color: color-mix(in srgb, var(--newtab-background-color) 85%, transparent);
|
||||
--newtab-textbox-focus-color: var(--newtab-primary-action-background);
|
||||
--newtab-textbox-focus-boxshadow: 0 0 0 1px var(--newtab-primary-action-background), 0 0 0 4px rgba(var(--newtab-primary-action-background), 0.3);
|
||||
--newtab-button-secondary-color: inherit;
|
||||
}
|
||||
:root[lwt-newtab-brighttext] {
|
||||
--newtab-background-color: #2B2A33;
|
||||
--newtab-background-color-secondary: #42414d;
|
||||
--newtab-text-primary-color: #fbfbfe;
|
||||
--newtab-primary-action-background: #00ddff;
|
||||
--newtab-primary-action-background-pocket: #00ddff;
|
||||
--newtab-primary-action-background-pocket-dimmed: color-mix(in srgb, var(--newtab-primary-action-background) 25%, transparent);
|
||||
--newtab-primary-element-hover-color: color-mix(in srgb, var(--newtab-primary-action-background) 55%, #FFF);
|
||||
--newtab-primary-element-hover-pocket-color: color-mix(in srgb, var(--newtab-primary-action-background-pocket) 55%, #FFF);
|
||||
--newtab-element-hover-color: color-mix(in srgb, var(--newtab-background-color) 80%, #FFF);
|
||||
--newtab-element-active-color: color-mix(in srgb, var(--newtab-background-color) 60%, #FFF);
|
||||
--newtab-element-secondary-color: color-mix(in srgb, currentColor 10%, transparent);
|
||||
--newtab-element-secondary-hover-color: color-mix(in srgb, currentColor 17%, transparent);
|
||||
--newtab-element-secondary-active-color: color-mix(in srgb, currentColor 30%, transparent);
|
||||
--newtab-border-color: color-mix(in srgb, var(--newtab-background-color) 75%, #FFF);
|
||||
--newtab-primary-element-text-color: #2b2a33;
|
||||
--newtab-wordmark-color: #fbfbfe;
|
||||
--newtab-status-success: #7C6;
|
||||
}
|
||||
|
||||
@media (prefers-contrast) {
|
||||
:root {
|
||||
--newtab-text-secondary-color: var(--newtab-text-primary-color);
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px;
|
||||
-moz-context-properties: fill;
|
||||
display: inline-block;
|
||||
color: var(--newtab-text-primary-color);
|
||||
fill: currentColor;
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
width: 16px;
|
||||
}
|
||||
.icon.icon-spacer {
|
||||
margin-inline-end: 8px;
|
||||
}
|
||||
.icon.icon-small-spacer {
|
||||
margin-inline-end: 6px;
|
||||
}
|
||||
.icon.icon-button-style {
|
||||
fill: var(--newtab-text-secondary-color);
|
||||
border: 0;
|
||||
}
|
||||
.icon.icon-button-style:focus, .icon.icon-button-style:hover {
|
||||
fill: var(--newtab-text-primary-color);
|
||||
}
|
||||
.icon.icon-bookmark-added {
|
||||
background-image: url("chrome://browser/skin/bookmark.svg");
|
||||
}
|
||||
.icon.icon-bookmark-hollow {
|
||||
background-image: url("chrome://browser/skin/bookmark-hollow.svg");
|
||||
}
|
||||
.icon.icon-clear-input {
|
||||
background-image: url("chrome://global/skin/icons/close-fill.svg");
|
||||
}
|
||||
.icon.icon-delete {
|
||||
background-image: url("chrome://global/skin/icons/delete.svg");
|
||||
}
|
||||
.icon.icon-search {
|
||||
background-image: url("chrome://global/skin/icons/search-glass.svg");
|
||||
}
|
||||
.icon.icon-modal-delete {
|
||||
flex-shrink: 0;
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-modal-delete-20.svg");
|
||||
background-size: 32px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
.icon.icon-mail {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-mail-16.svg");
|
||||
}
|
||||
.icon.icon-dismiss {
|
||||
background-image: url("chrome://global/skin/icons/close.svg");
|
||||
}
|
||||
.icon.icon-info {
|
||||
background-image: url("chrome://global/skin/icons/info.svg");
|
||||
}
|
||||
.icon.icon-new-window {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-newWindow-16.svg");
|
||||
}
|
||||
.icon.icon-new-window:dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
.icon.icon-new-window-private {
|
||||
background-image: url("chrome://browser/skin/privateBrowsing.svg");
|
||||
}
|
||||
.icon.icon-settings {
|
||||
background-image: url("chrome://global/skin/icons/settings.svg");
|
||||
}
|
||||
.icon.icon-pin {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-pin-16.svg");
|
||||
}
|
||||
.icon.icon-pin:dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
.icon.icon-unpin {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-unpin-16.svg");
|
||||
}
|
||||
.icon.icon-unpin:dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
.icon.icon-edit {
|
||||
background-image: url("chrome://global/skin/icons/edit.svg");
|
||||
}
|
||||
.icon.icon-pocket {
|
||||
background-image: url("chrome://global/skin/icons/pocket.svg");
|
||||
}
|
||||
.icon.icon-pocket-save {
|
||||
background-image: url("chrome://global/skin/icons/pocket.svg");
|
||||
fill: #FFF;
|
||||
}
|
||||
.icon.icon-pocket-delete {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-pocket-delete-16.svg");
|
||||
}
|
||||
.icon.icon-pocket-archive {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-pocket-archive-16.svg");
|
||||
}
|
||||
.icon.icon-history-item {
|
||||
background-image: url("chrome://browser/skin/history.svg");
|
||||
}
|
||||
.icon.icon-trending {
|
||||
background-image: url("chrome://browser/skin/trending.svg");
|
||||
transform: translateY(2px);
|
||||
}
|
||||
.icon.icon-now {
|
||||
background-image: url("chrome://browser/skin/history.svg");
|
||||
}
|
||||
.icon.icon-topsites {
|
||||
background-image: url("chrome://browser/skin/topsites.svg");
|
||||
}
|
||||
.icon.icon-pin-small {
|
||||
background-image: url("chrome://browser/skin/pin-12.svg");
|
||||
background-size: 12px;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
.icon.icon-pin-small:dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
.icon.icon-check {
|
||||
background-image: url("chrome://global/skin/icons/check.svg");
|
||||
}
|
||||
.icon.icon-download {
|
||||
background-image: url("chrome://browser/skin/downloads/downloads.svg");
|
||||
}
|
||||
.icon.icon-copy {
|
||||
background-image: url("chrome://global/skin/icons/edit-copy.svg");
|
||||
}
|
||||
.icon.icon-open-file {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-open-file-16.svg");
|
||||
}
|
||||
.icon.icon-webextension {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-webextension-16.svg");
|
||||
}
|
||||
.icon.icon-highlights {
|
||||
background-image: url("chrome://global/skin/icons/highlights.svg");
|
||||
}
|
||||
.icon.icon-arrowhead-down {
|
||||
background-image: url("chrome://global/skin/icons/arrow-down.svg");
|
||||
}
|
||||
.icon.icon-arrowhead-down-small {
|
||||
background-image: url("chrome://global/skin/icons/arrow-down-12.svg");
|
||||
background-size: 12px;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
.icon.icon-arrowhead-forward-small {
|
||||
background-image: url("chrome://global/skin/icons/arrow-right-12.svg");
|
||||
background-size: 12px;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
.icon.icon-arrowhead-forward-small:dir(rtl) {
|
||||
background-image: url("chrome://global/skin/icons/arrow-left-12.svg");
|
||||
}
|
||||
.icon.icon-arrowhead-up {
|
||||
background-image: url("chrome://global/skin/icons/arrow-up.svg");
|
||||
}
|
||||
.icon.icon-add {
|
||||
background-image: url("chrome://global/skin/icons/plus.svg");
|
||||
}
|
||||
.icon.icon-minimize {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-minimize-16.svg");
|
||||
}
|
||||
.icon.icon-maximize {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/glyph-maximize-16.svg");
|
||||
}
|
||||
.icon.icon-arrow {
|
||||
background-image: url("chrome://global/skin/icons/arrow-right-12.svg");
|
||||
}
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
border-radius: 2px;
|
||||
border: 0;
|
||||
font-family: inherit;
|
||||
padding: 8px 15px;
|
||||
margin-inline-start: 12px;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tall .ASRouterButton {
|
||||
margin-inline-start: 20px;
|
||||
}
|
||||
.ASRouterButton.test-only {
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
}
|
||||
.ASRouterButton.primary {
|
||||
border: 1px solid var(--newtab-primary-action-background);
|
||||
background-color: var(--newtab-primary-action-background);
|
||||
color: var(--newtab-primary-element-text-color);
|
||||
}
|
||||
.ASRouterButton.primary:hover {
|
||||
background-color: var(--newtab-primary-element-hover-color);
|
||||
}
|
||||
.ASRouterButton.primary:active {
|
||||
background-color: var(--newtab-primary-element-active-color);
|
||||
}
|
||||
.ASRouterButton.slim {
|
||||
border: 1px solid var(--newtab-border-color);
|
||||
margin-inline-start: 0;
|
||||
font-size: 12px;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
.ASRouterButton.slim:hover, .ASRouterButton.slim:focus {
|
||||
box-shadow: 0 0 0 5px var(--newtab-element-secondary-color);
|
||||
transition: box-shadow 150ms;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Ubuntu, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
/**
|
||||
* These styles are copied verbatim from _activity-stream.scss in order to maintain
|
||||
* a continuity of styling while also decoupling from the newtab code. This should
|
||||
* be removed when about:asrouter starts using the default in-content style sheets.
|
||||
*/
|
||||
.button,
|
||||
.actions button {
|
||||
background-color: var(--newtab-button-secondary-color);
|
||||
border: 1px solid var(--newtab-border-color);
|
||||
border-radius: 4px;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
margin-bottom: 15px;
|
||||
padding: 10px 30px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.button:hover:not(.dismiss), .button:focus:not(.dismiss),
|
||||
.actions button:hover:not(.dismiss),
|
||||
.actions button:focus:not(.dismiss) {
|
||||
box-shadow: 0 0 0 5px var(--newtab-element-secondary-color);
|
||||
transition: box-shadow 150ms;
|
||||
}
|
||||
.button.dismiss,
|
||||
.actions button.dismiss {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.button.primary, .button.done,
|
||||
.actions button.primary,
|
||||
.actions button.done {
|
||||
background-color: var(--newtab-primary-action-background);
|
||||
border: solid 1px var(--newtab-primary-action-background);
|
||||
color: var(--newtab-primary-element-text-color);
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
|
||||
.asrouter-admin {
|
||||
max-width: 1300px;
|
||||
font-size: 14px;
|
||||
padding-inline-start: 240px;
|
||||
color: var(--newtab-text-primary-color);
|
||||
}
|
||||
.asrouter-admin.collapsed {
|
||||
display: none;
|
||||
}
|
||||
.asrouter-admin .sidebar {
|
||||
inset-inline-start: 0;
|
||||
position: fixed;
|
||||
width: 240px;
|
||||
}
|
||||
.asrouter-admin .sidebar ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.asrouter-admin .sidebar li a {
|
||||
padding: 10px 34px;
|
||||
display: block;
|
||||
color: var(--lwt-sidebar-text-color);
|
||||
}
|
||||
.asrouter-admin .sidebar li a:hover {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
.asrouter-admin h1 {
|
||||
font-weight: 200;
|
||||
font-size: 32px;
|
||||
}
|
||||
.asrouter-admin h2 .button,
|
||||
.asrouter-admin p .button {
|
||||
font-size: 14px;
|
||||
padding: 6px 12px;
|
||||
margin-inline-start: 5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.asrouter-admin .general-textarea {
|
||||
direction: ltr;
|
||||
width: 740px;
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
resize: none;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
}
|
||||
.asrouter-admin .wnp-textarea {
|
||||
direction: ltr;
|
||||
width: 740px;
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
resize: none;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
}
|
||||
.asrouter-admin .json-button {
|
||||
display: inline-flex;
|
||||
font-size: 10px;
|
||||
padding: 4px 10px;
|
||||
margin-bottom: 6px;
|
||||
margin-inline-end: 4px;
|
||||
}
|
||||
.asrouter-admin .json-button:hover {
|
||||
background-color: var(--newtab-element-hover-color);
|
||||
box-shadow: none;
|
||||
}
|
||||
.asrouter-admin table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.asrouter-admin table.minimal-table {
|
||||
border-collapse: collapse;
|
||||
border: 1px solid var(--newtab-border-color);
|
||||
}
|
||||
.asrouter-admin table.minimal-table td {
|
||||
padding: 8px;
|
||||
}
|
||||
.asrouter-admin table.minimal-table td:first-child {
|
||||
width: 1%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.asrouter-admin table.minimal-table td:not(:first-child) {
|
||||
font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace;
|
||||
}
|
||||
.asrouter-admin table.errorReporting tr {
|
||||
border: 1px solid var(--newtab-background-color-secondary);
|
||||
}
|
||||
.asrouter-admin table.errorReporting td {
|
||||
padding: 4px;
|
||||
}
|
||||
.asrouter-admin table.errorReporting td[rowspan] {
|
||||
border: 1px solid var(--newtab-background-color-secondary);
|
||||
}
|
||||
.asrouter-admin .sourceLabel {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.asrouter-admin .sourceLabel.isDisabled {
|
||||
background: rgba(215, 0, 34, 0.3);
|
||||
color: var(--newtab-status-error);
|
||||
}
|
||||
.asrouter-admin .message-item:first-child td {
|
||||
border-top: 1px solid var(--newtab-border-color);
|
||||
}
|
||||
.asrouter-admin .message-item td {
|
||||
vertical-align: top;
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid var(--newtab-border-color);
|
||||
}
|
||||
.asrouter-admin .message-item td.min {
|
||||
width: 1%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.asrouter-admin .message-item td.message-summary {
|
||||
width: 60%;
|
||||
}
|
||||
.asrouter-admin .message-item td.button-column {
|
||||
width: 15%;
|
||||
}
|
||||
.asrouter-admin .message-item td:first-child {
|
||||
border-inline-start: 1px solid var(--newtab-border-color);
|
||||
}
|
||||
.asrouter-admin .message-item td:last-child {
|
||||
border-inline-end: 1px solid var(--newtab-border-color);
|
||||
}
|
||||
.asrouter-admin .message-item.blocked .message-id,
|
||||
.asrouter-admin .message-item.blocked .message-summary {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.asrouter-admin .message-item.blocked .message-id {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.asrouter-admin .message-item .message-id {
|
||||
font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
.asrouter-admin .providerUrl {
|
||||
font-size: 12px;
|
||||
}
|
||||
.asrouter-admin pre {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
max-width: 750px;
|
||||
overflow: auto;
|
||||
font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace;
|
||||
}
|
||||
.asrouter-admin .errorState {
|
||||
border: 1px solid var(--newtab-status-error);
|
||||
}
|
||||
.asrouter-admin .helpLink {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 3px;
|
||||
align-items: center;
|
||||
}
|
||||
.asrouter-admin .helpLink a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.asrouter-admin .helpLink .icon {
|
||||
min-width: 18px;
|
||||
min-height: 18px;
|
||||
}
|
||||
.asrouter-admin .ds-component {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.asrouter-admin .modalOverlayInner {
|
||||
height: 80%;
|
||||
}
|
||||
.asrouter-admin .clearButton {
|
||||
border: 0;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
}
|
||||
.asrouter-admin .clearButton:hover {
|
||||
background: var(--newtab-element-hover-color);
|
||||
}
|
||||
.asrouter-admin .collapsed {
|
||||
display: none;
|
||||
}
|
||||
.asrouter-admin .icon {
|
||||
display: inline-table;
|
||||
cursor: pointer;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
.asrouter-admin .button:disabled, .asrouter-admin .button:disabled:active {
|
||||
opacity: 0.5;
|
||||
cursor: unset;
|
||||
box-shadow: none;
|
||||
}
|
||||
.asrouter-admin .impressions-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
.asrouter-admin .impressions-section .impressions-item {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--newtab-border-color);
|
||||
border-radius: 5px;
|
||||
}
|
||||
.asrouter-admin .impressions-section .impressions-item .impressions-inner-box {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.asrouter-admin .impressions-section .impressions-item .impressions-category {
|
||||
font-size: 1.15em;
|
||||
white-space: nowrap;
|
||||
flex-grow: 0.1;
|
||||
}
|
||||
.asrouter-admin .impressions-section .impressions-item .impressions-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.asrouter-admin .impressions-section .impressions-item .impressions-buttons button {
|
||||
margin: 0;
|
||||
}
|
||||
.asrouter-admin .impressions-section .impressions-item .impressions-editor {
|
||||
display: flex;
|
||||
flex-grow: 1.5;
|
||||
}
|
||||
.asrouter-admin .impressions-section .impressions-item .impressions-editor .general-textarea {
|
||||
width: auto;
|
||||
flex-grow: 1;
|
||||
}
|
7
browser/components/asrouter/content/render.js
Normal file
7
browser/components/asrouter/content/render.js
Normal file
@ -0,0 +1,7 @@
|
||||
/* 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/. */
|
||||
"use strict";
|
||||
|
||||
// exported by asrouter-admin.bundle.js
|
||||
window.ASRouterAdminRenderUtils.renderASRouterAdmin();
|
9
browser/components/asrouter/jar.mn
Normal file
9
browser/components/asrouter/jar.mn
Normal file
@ -0,0 +1,9 @@
|
||||
# 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/.
|
||||
|
||||
browser.jar:
|
||||
content/browser/asrouter/asrouter-admin.html (content/asrouter-admin.html)
|
||||
content/browser/asrouter/asrouter-admin.bundle.js (content/asrouter-admin.bundle.js)
|
||||
content/browser/asrouter/components/ASRouterAdmin/ASRouterAdmin.css (content/components/ASRouterAdmin/ASRouterAdmin.css)
|
||||
content/browser/asrouter/render.js (content/render.js)
|
10
browser/components/asrouter/moz.build
Normal file
10
browser/components/asrouter/moz.build
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
JAR_MANIFESTS += ["jar.mn"]
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Firefox", "Messaging System")
|
7292
browser/components/asrouter/package-lock.json
generated
Normal file
7292
browser/components/asrouter/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
64
browser/components/asrouter/package.json
Normal file
64
browser/components/asrouter/package.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "ASRouter",
|
||||
"description": "Task running for ASRouter",
|
||||
"version": "1.0.0",
|
||||
"author": "Mozilla (https://mozilla.org/)",
|
||||
"dependencies": {
|
||||
"@fluent/bundle": "0.17.1",
|
||||
"@fluent/react": "0.15.0",
|
||||
"react": "16.13.1",
|
||||
"react-dom": "16.13.1",
|
||||
"react-redux": "7.2.6",
|
||||
"redux": "4.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-optional-chaining": "7.16.0",
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"babel-loader": "8.2.3",
|
||||
"mocha": "9.1.3",
|
||||
"npm-run-all": "4.1.5",
|
||||
"sass": "1.43.4",
|
||||
"sinon": "12.0.1",
|
||||
"webpack": "5.56.0",
|
||||
"webpack-cli": "4.9.1",
|
||||
"yamscripts": "0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"firefox": ">=45.0 <=*",
|
||||
"//": "when changing node versions, also edit .nvmrc",
|
||||
"node": "16.19.*",
|
||||
"npm": "8.19.3"
|
||||
},
|
||||
"license": "MPL-2.0",
|
||||
"config": {
|
||||
"mc_root": "../../..",
|
||||
"asrouter_path": "browser/components/asrouter"
|
||||
},
|
||||
"scripts": {
|
||||
"bundle": "npm-run-all bundle:*",
|
||||
"bundle:admin": "webpack-cli --config webpack.asrouter-admin.config.js",
|
||||
"bundle:css": "sass content-src:content --no-source-map",
|
||||
"watchmc": "npm-run-all --parallel watchmc:*",
|
||||
"watchmc:bundle": "npm run bundle:admin -- --env development -w",
|
||||
"watchmc:css": "npm run bundle:css -- --source-map --embed-sources --embed-source-map -w",
|
||||
"testmc": "npm-run-all testmc:*",
|
||||
"testmc:lint": "npm run lint",
|
||||
"testmc:build": "npm run bundle:admin",
|
||||
"testmc:unit": "karma start karma.mc.config.js",
|
||||
"tddmc": "karma start karma.mc.config.js --tdd",
|
||||
"debugcoverage": "open logs/coverage/lcov-report/index.html",
|
||||
"lint": "npm-run-all lint:*",
|
||||
"lint:codespell": "(cd $npm_package_config_mc_root && ./mach lint -l codespell $npm_package_config_asrouter_path)",
|
||||
"lint:eslint": "(cd $npm_package_config_mc_root && ./mach lint -l eslint $npm_package_config_asrouter_path)",
|
||||
"lint:license": "(cd $npm_package_config_mc_root && ./mach lint -l license $npm_package_config_asrouter_path)",
|
||||
"lint:stylelint": "(cd $npm_package_config_mc_root && ./mach lint -l stylelint $npm_package_config_asrouter_path)",
|
||||
"test": "npm run testmc",
|
||||
"tdd": "npm run tddmc",
|
||||
"fix": "npm-run-all fix:*",
|
||||
"fix:eslint": "npm run lint:eslint -- --fix",
|
||||
"fix:stylelint": "npm run lint:stylelint -- --fix",
|
||||
"help": "yamscripts help",
|
||||
"yamscripts": "yamscripts compile",
|
||||
"__": "# NOTE: THESE SCRIPTS ARE COMPILED!!! EDIT yamscripts.yml instead!!!"
|
||||
}
|
||||
}
|
34
browser/components/asrouter/webpack.asrouter-admin.config.js
Normal file
34
browser/components/asrouter/webpack.asrouter-admin.config.js
Normal file
@ -0,0 +1,34 @@
|
||||
/* 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/. */
|
||||
|
||||
const path = require("path");
|
||||
const config = require("../newtab/webpack.system-addon.config.js");
|
||||
const webpack = require("webpack");
|
||||
const absolute = relPath => path.join(__dirname, relPath);
|
||||
const banner = `
|
||||
NOTE: This file is generated by webpack from ASRouterAdmin.jsx
|
||||
using the npm bundle task.
|
||||
`;
|
||||
module.exports = Object.assign({}, config(), {
|
||||
entry: absolute("content-src/components/ASRouterAdmin/ASRouterAdmin.jsx"),
|
||||
output: {
|
||||
path: absolute("content"),
|
||||
filename: "asrouter-admin.bundle.js",
|
||||
library: "ASRouterAdminRenderUtils",
|
||||
},
|
||||
externals: {
|
||||
"prop-types": "PropTypes",
|
||||
react: "React",
|
||||
"react-dom": "ReactDOM",
|
||||
},
|
||||
plugins: [new webpack.BannerPlugin(banner)],
|
||||
// This resolve config allows us to import with paths relative to the root directory, e.g. "lib/ActivityStream.jsm"
|
||||
resolve: {
|
||||
extensions: [".js", ".jsx"],
|
||||
alias: {
|
||||
newtab: absolute("../newtab"),
|
||||
common: absolute("../newtab/common"),
|
||||
},
|
||||
},
|
||||
});
|
44
browser/components/asrouter/yamscripts.yml
Normal file
44
browser/components/asrouter/yamscripts.yml
Normal file
@ -0,0 +1,44 @@
|
||||
# This file compiles to package.json scripts.
|
||||
# When you add or modify anything, you *MUST* run:
|
||||
# npm run yamscripts
|
||||
# to compile your changes.
|
||||
|
||||
scripts:
|
||||
# bundle: Build all assets for ASRouter
|
||||
bundle:
|
||||
admin: webpack-cli --config webpack.asrouter-admin.config.js
|
||||
css: sass content-src:content --no-source-map
|
||||
|
||||
# watchmc: Automatically rebuild when files are changed. NOTE: Includes sourcemaps, do not use for profiling/perf testing.
|
||||
watchmc:
|
||||
_parallel: true
|
||||
bundle: =>bundle:admin -- --env development -w
|
||||
css: =>bundle:css -- --source-map --embed-sources --embed-source-map -w
|
||||
|
||||
testmc:
|
||||
lint: =>lint
|
||||
build: =>bundle:admin
|
||||
unit: karma start karma.mc.config.js
|
||||
|
||||
tddmc: karma start karma.mc.config.js --tdd
|
||||
|
||||
debugcoverage: open logs/coverage/lcov-report/index.html
|
||||
|
||||
# lint: Run various linters with mach or local dev dependencies
|
||||
lint:
|
||||
codespell: (cd $npm_package_config_mc_root && ./mach lint -l codespell $npm_package_config_asrouter_path)
|
||||
eslint: (cd $npm_package_config_mc_root && ./mach lint -l eslint $npm_package_config_asrouter_path)
|
||||
license: (cd $npm_package_config_mc_root && ./mach lint -l license $npm_package_config_asrouter_path)
|
||||
stylelint: (cd $npm_package_config_mc_root && ./mach lint -l stylelint $npm_package_config_asrouter_path)
|
||||
|
||||
# test: Run all tests once
|
||||
test: =>testmc
|
||||
|
||||
# tdd: Run content tests continuously
|
||||
tdd: =>tddmc
|
||||
|
||||
fix:
|
||||
# Note that since we're currently running eslint-plugin-prettier,
|
||||
# running fix:eslint will also reformat changed JS files using prettier.
|
||||
eslint: =>lint:eslint -- --fix
|
||||
stylelint: =>lint:stylelint -- --fix
|
@ -30,6 +30,7 @@ DIRS += [
|
||||
"about",
|
||||
"aboutlogins",
|
||||
"aboutwelcome",
|
||||
"asrouter",
|
||||
"attribution",
|
||||
"contentanalysis",
|
||||
"contextualidentity",
|
||||
|
@ -1116,6 +1116,7 @@ class _ASRouter {
|
||||
userPrefs: lazy.ASRouterPreferences.getAllUserPreferences(),
|
||||
targetingParameters,
|
||||
errors: this.errors,
|
||||
devtoolsEnabled: lazy.ASRouterPreferences.devtoolsEnabled,
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -1594,6 +1594,7 @@ describe("ASRouter", () => {
|
||||
userPrefs: ASRouterPreferences.getAllUserPreferences(),
|
||||
targetingParameters: {},
|
||||
errors: Router.errors,
|
||||
devtoolsEnabled: ASRouterPreferences.devtoolsEnabled,
|
||||
});
|
||||
|
||||
assert.deepEqual(msg, expected);
|
||||
|
@ -4,6 +4,9 @@ build/vs/vs2022.yaml
|
||||
browser/components/aboutwelcome/content/aboutwelcome.bundle.js
|
||||
browser/components/aboutwelcome/logs/
|
||||
browser/components/aboutwelcome/node_modules/
|
||||
browser/components/asrouter/node_modules/
|
||||
browser/components/asrouter/content/asrouter-admin.bundle.js
|
||||
browser/components/asrouter/logs/
|
||||
browser/components/newtab/content-src/asrouter/schemas/BackgroundTaskMessagingExperiment.schema.json
|
||||
browser/components/newtab/content-src/asrouter/schemas/MessagingExperiment.schema.json
|
||||
browser/components/newtab/logs/
|
||||
|
Loading…
Reference in New Issue
Block a user