diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c51ffe3d17..30143ee4c3 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -15,14 +15,14 @@ jobs: days-before-issue-stale: 730 days-before-issue-close: 1 stale-issue-label: "stale" - stale-issue-message: > + stale-issue-message: > We're in the process of cleaning up issues on this project in order to ensure we're able to stay on top of high priority bugs and feature requests. As a part of this process, we're automatically closing any issues that have had no activity within the last two years, including this one, since the codebase has changed dramatically in that time. - If you feel this is still relevant, please [file a new issue](https://github.com/WPO-Foundation/webpagetest/issues/new/choose) using the relevant issue template so we can get it prioritized. + If you feel this is still relevant, please [file a new issue](https://github.com/catchpoint/WebPageTest/issues/new/choose) using the relevant issue template so we can get it prioritized. Thanks! close-issue-message: " " days-before-pr-stale: -1 days-before-pr-close: -1 ascending: true operations-per-run: 2000 - repo-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/LICENSE_FAQ.md b/LICENSE_FAQ.md index bb5b5d694a..d2a089e461 100644 --- a/LICENSE_FAQ.md +++ b/LICENSE_FAQ.md @@ -1,76 +1,77 @@ -# WebPageTest by Catchpoint Licensing FAQ +# WebPageTest by Catchpoint Licensing FAQ ## Executive Summary -The WebPageTest code is free to use under the Polyform Shield license, a source-available license. As long as you are not creating a product or service that competes with Catchpoint’s offerings then you are free to do whatever you like with the WebPageTest code, including using it for your own internal use or creating non-competing commercial products from it. In fact, we encourage using the WebPageTest code to build your own value-added applications. -## What is the Polyform Shield License? +The WebPageTest code is free to use under the Polyform Shield license, a source-available license. As long as you are not creating a product or service that competes with Catchpoint’s offerings then you are free to do whatever you like with the WebPageTest code, including using it for your own internal use or creating non-competing commercial products from it. In fact, we encourage using the WebPageTest code to build your own value-added applications. -More information about Polyform licenses, including the Shield License, can be found here: https://polyformproject.org, and the Shield License is here: https://polyformproject.org/licenses/shield/1.0.0/. +## What is the Polyform Shield License? -We chose the Polyform Shield license because it provides a standard community-accepted license that provides the necessary protections for a commercial product while keeping the code as open as possible. +More information about Polyform licenses, including the Shield License, can be found here: https://polyformproject.org, and the Shield License is here: https://polyformproject.org/licenses/shield/1.0.0/. -A prior version of the WebPageTest code was released under the BSD and Apache 2.0 licenses. A branch of the code under that license is available [here](https://github.com/WPO-Foundation/webpagetest/tree/apache) for anyone in the community who wants to continue to use the code under that license or contribute to its maintenance. +We chose the Polyform Shield license because it provides a standard community-accepted license that provides the necessary protections for a commercial product while keeping the code as open as possible. -## What does this mean for my access and usage of the source code? +A prior version of the WebPageTest code was released under the BSD and Apache 2.0 licenses. A branch of the code under that license is available [here](https://github.com/catchpoint/WebPageTest/tree/apache) for anyone in the community who wants to continue to use the code under that license or contribute to its maintenance. -You can access the WebPageTest source code, and download, modify, or redistribute it with one limitation: you can’t use the WebPageTest source code to make a product that competes with Catchpoint. We’ve excerpted the relevant license language here: +## What does this mean for my access and usage of the source code? -> “Any purpose is a permitted purpose, except for providing any product that competes with the software or any product the licensor or any of its affiliates provides using the software.” +You can access the WebPageTest source code, and download, modify, or redistribute it with one limitation: you can’t use the WebPageTest source code to make a product that competes with Catchpoint. We’ve excerpted the relevant license language here: -For clarity, “permitted purposes” exclude providing any software-as a-service, platform-as-a-service, infrastructure-as-a-service or other similar online service that competes with Catchpoint products or services. +> “Any purpose is a permitted purpose, except for providing any product that competes with the software or any product the licensor or any of its affiliates provides using the software.” -We expect that almost all users of the WebPageTest will have no trouble abiding by this license. We hope this explanation is helpful, but the legal requirements are in the actual language of the license, not this FAQ. +For clarity, “permitted purposes” exclude providing any software-as a-service, platform-as-a-service, infrastructure-as-a-service or other similar online service that competes with Catchpoint products or services. -While our prior open source version is still available, we may no longer be maintaining this version. +We expect that almost all users of the WebPageTest will have no trouble abiding by this license. We hope this explanation is helpful, but the legal requirements are in the actual language of the license, not this FAQ. -If you are interested in a license of WebPageTest software on commercial licensing terms, please contact us at [webpagetest@catchpoint.com](mailto:webpagetest@catchpoint.com), and we would be happy to answer any questions and help you set up an enterprise relationship. +While our prior open source version is still available, we may no longer be maintaining this version. -## Can I embed WebPageTest source code licensed under the Polyform Shield License in a software I distribute? +If you are interested in a license of WebPageTest software on commercial licensing terms, please contact us at [webpagetest@catchpoint.com](mailto:webpagetest@catchpoint.com), and we would be happy to answer any questions and help you set up an enterprise relationship. -Yes, you are still able to do so, as long as that product does not compete with Catchpoint products and services. +## Can I embed WebPageTest source code licensed under the Polyform Shield License in a software I distribute? -## Can I embed Polyform Shield source code in a new SaaS offering? +Yes, you are still able to do so, as long as that product does not compete with Catchpoint products and services. + +## Can I embed Polyform Shield source code in a new SaaS offering? Yes, but only as long as your SaaS offering does not compete with Catchpoint products and services. -## Can I modify some of the WebPageTest source code licensed under the Polyform Shield License? +## Can I modify some of the WebPageTest source code licensed under the Polyform Shield License? -Yes, as long as your use case is covered by the “permitted purpose” defined in the license. +Yes, as long as your use case is covered by the “permitted purpose” defined in the license. -## Under the terms of the Polyform Shield License, can I create a competing product but give it away for free? +## Under the terms of the Polyform Shield License, can I create a competing product but give it away for free? -No; whether a fee is charged or not does change whether your product competes. A free-of-charge product that competes with Catchpoint products or services is still prohibited. +No; whether a fee is charged or not does change whether your product competes. A free-of-charge product that competes with Catchpoint products or services is still prohibited. -## Is the Polyform Shield License open source? +## Is the Polyform Shield License open source? -They are not exactly the same. The Polyform Shield License permits many of the same actions that “true” open source licenses do, such as downloading, modifying, and distributing the source code, but it does not permit the use case of creating a product “that competes with the software or any product the licensor or any of its affiliates provides,” as described above. The Polyform Shield License is technically source available, rather than open source, and we will refer to it as “source available.” The phrase “open source,” used strictly, refers to licenses adhering to a specific set of criteria published by the Open Source Initiative. +They are not exactly the same. The Polyform Shield License permits many of the same actions that “true” open source licenses do, such as downloading, modifying, and distributing the source code, but it does not permit the use case of creating a product “that competes with the software or any product the licensor or any of its affiliates provides,” as described above. The Polyform Shield License is technically source available, rather than open source, and we will refer to it as “source available.” The phrase “open source,” used strictly, refers to licenses adhering to a specific set of criteria published by the Open Source Initiative. -## When will the Polyform Shield License be effective? +## When will the Polyform Shield License be effective? -It will apply to WebPageTest software released as of November 1, 2020, and later releases. Previous releases and any bug fixes to such releases will remain under the BSD and Apache 2.0 licenses. +It will apply to WebPageTest software released as of November 1, 2020, and later releases. Previous releases and any bug fixes to such releases will remain under the BSD and Apache 2.0 licenses. -## Does the Polyform Shield License impose a general prohibition against competing with Catchpoint? +## Does the Polyform Shield License impose a general prohibition against competing with Catchpoint? -Yes, in the sense that you cannot use our software to compete with any of our products or services; see the definition of “permitted purpose” above. +Yes, in the sense that you cannot use our software to compete with any of our products or services; see the definition of “permitted purpose” above. -## I’m confused about what use cases are competitive. What if future Catchpoint products compete with mine? +## I’m confused about what use cases are competitive. What if future Catchpoint products compete with mine? -Competitive products are evaluated relative to the Catchpoint offerings at the time your product is created. If you create a product that does not compete with current Catchpoint offerings, then you can continue to use the WebPageTest software even if a future Catchpoint offering does compete. Please see the license for the exact limitations. +Competitive products are evaluated relative to the Catchpoint offerings at the time your product is created. If you create a product that does not compete with current Catchpoint offerings, then you can continue to use the WebPageTest software even if a future Catchpoint offering does compete. Please see the license for the exact limitations. -## Can I still use older versions of the WebPageTest software? +## Can I still use older versions of the WebPageTest software? -Yes; the new license terms don’t alter your ability to use older versions of the WebPageTest software under their open source license. +Yes; the new license terms don’t alter your ability to use older versions of the WebPageTest software under their open source license. -## My company doesn’t permit employees to use code with a non-commercial restriction. Can I still use WebPageTest under the new Polyform Shield license? +## My company doesn’t permit employees to use code with a non-commercial restriction. Can I still use WebPageTest under the new Polyform Shield license? -The only commercial restriction imposed is set out in the “permitted purposes” described above: a product that competes with Catchpoint. This is a much narrower restriction than a “non-commercial” restriction. If you want to use the software and are having trouble getting it approved by your company, contact us at [webpagetest@catchpoint.com](mailto:webpagetest@catchpoint.com), and we may be able to help. +The only commercial restriction imposed is set out in the “permitted purposes” described above: a product that competes with Catchpoint. This is a much narrower restriction than a “non-commercial” restriction. If you want to use the software and are having trouble getting it approved by your company, contact us at [webpagetest@catchpoint.com](mailto:webpagetest@catchpoint.com), and we may be able to help. -## Is the Polyform Shield License a EULA? +## Is the Polyform Shield License a EULA? -No, a “EULA” is an end user license agreement, and is almost always used for binary software only. The Polyform Shield License gives you other rights in addition to use, such as modification and distribution, in addition to use, subject only to the “permitted purposes” clause set out above. +No, a “EULA” is an end user license agreement, and is almost always used for binary software only. The Polyform Shield License gives you other rights in addition to use, such as modification and distribution, in addition to use, subject only to the “permitted purposes” clause set out above. -## Why did Catchpoint make this change? +## Why did Catchpoint make this change? -This lets us invest heavily in code that we distribute for free, while sustaining a healthy business that funds this investment. +This lets us invest heavily in code that we distribute for free, while sustaining a healthy business that funds this investment. -This change is similar to and made for similar reasons as other companies that have gone through similar licensing adjustments. We still believe in the WebPageTest project and its availability as a resource for the community. \ No newline at end of file +This change is similar to and made for similar reasons as other companies that have gone through similar licensing adjustments. We still believe in the WebPageTest project and its availability as a resource for the community. diff --git a/README.md b/README.md index eca4f505c3..feefdbf328 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,9 @@ This is the official repository for the performance-testing code that runs at [webpagetest.org](https://www.webpagetest.org). - 🥡 [Install your own instance](https://docs.webpagetest.org/private-instances/) -- 📕 [Documentation](https://github.com/WPO-Foundation/webpagetest-docs) +- 📕 [Documentation](https://github.com/catchpoint/WebPageTest.docs) - 🕒 [Changelog](https://docs.webpagetest.org/change-log) -- 🌐 [Cross-platform browser agent](https://github.com/WPO-Foundation/wptagent) -- [WPT website global header repo](https://github.com/WebPageTest/wpt-header) and [documentation](https://wpt-header.netlify.app/) +- 🌐 [Cross-platform browser agent](https://github.com/catchpoint/WebPageTest.agent) - 💤 [REST API](https://docs.webpagetest.org/api/) examples: - 🐘 [`/bulktest`](/bulktest/): A PHP command-line tool that can submit a bulk set of tests, gather the results, and aggregate analyses. - 🐍 [`/batchtool`](/batchtool/): A Python tool that can submit a bulk set of tests and gather the results. diff --git a/bulktest/alexa-curated.txt b/bulktest/alexa-curated.txt index d524b80cb7..5f4f39e191 100644 --- a/bulktest/alexa-curated.txt +++ b/bulktest/alexa-curated.txt @@ -79,7 +79,7 @@ www.aol.com/ wenwen.sogou.com/ www.yelp.com/search?find_desc=dinner&find_loc=New+York%2C+NY&ns=1 ameblo.jp/ -https://github.com/WPO-Foundation/webpagetest +https://github.com/catchpoint/WebPageTest new.livejasmin.com/en/ www.slideshare.net/patrickmeenan www.w3schools.com/html/default.asp diff --git a/docker/local/Dockerfile-wptagent b/docker/local/Dockerfile-wptagent index 966045f6c8..6494cb7ce0 100644 --- a/docker/local/Dockerfile-wptagent +++ b/docker/local/Dockerfile-wptagent @@ -42,7 +42,7 @@ RUN ln -fs /usr/share/zoneinfo/$TIMEZONE /etc/localtime && apt install -y \ ttf-mscorefonts-installer fonts-noto fonts-roboto fonts-open-sans ffmpeg npm sudo curl xvfb # Get WPTAgent for dependecies -RUN git clone -b master https://github.com/WPO-Foundation/wptagent.git +RUN git clone -b master https://github.com/catchpoint/WebPageTest.agent.git ### UPDATE FONT CACHE ### RUN fc-cache -f -v diff --git a/docker/local/README.md b/docker/local/README.md index d86ce092ed..8dbeb06796 100644 --- a/docker/local/README.md +++ b/docker/local/README.md @@ -19,7 +19,7 @@ The reason for failure on WSL2 is because WSL2 does not have the network interfa Clone the project ```bash - git clone https://github.com/WPO-Foundation/webpagetest.git + git clone https://github.com/catchpoint/WebPageTest.git ``` Go to the project directory @@ -53,7 +53,7 @@ Since the Webpagetest container is packaged with an agent, we first need to stop #### #### ``` -Then follow the guide on how to install Wptagent (https://github.com/WPO-Foundation/wptagent). Once the Agent is working, which can be confirmed by running a local test with... +Then follow the guide on how to install [Wpt Agent](https://github.com/catchpoint/WebPageTest.agent). Once the Agent is working, which can be confirmed by running a local test with... ```bash python3 wptagent.py -vvvv --xvfb --testurl www.google.com --shaper none #Shaper doesn't work with my instance @@ -78,7 +78,7 @@ Adjusting Webpagetest Keys? Adjust them here `docker/local/wptconfig/keys.ini` Looking for more information setting up? Check Out - - `https://github.com/WPO-Foundation/wptserver-install` + - `https://github.com/catchpoint/WebPageTest.server-install` - `https://www.robinosborne.co.uk/2021/12/22/automate-your-webpagetest-private-instance-with-terraform-2021-edition/` diff --git a/docs/EC2/Server AMI.md b/docs/EC2/Server AMI.md index 385af05801..d417dced17 100644 --- a/docs/EC2/Server AMI.md +++ b/docs/EC2/Server AMI.md @@ -60,9 +60,9 @@ api_key=MyAPIKey headless=0 ``` -The full list of settings that can be specified is in [settings.ini.sample](https://github.com/WPO-Foundation/webpagetest/blob/master/www/settings/settings.ini.sample) +The full list of settings that can be specified is in [settings.ini.sample](https://github.com/catchpoint/WebPageTest/blob/master/www/settings/settings.ini.sample) -EC2 test agent AMIs can be found [here](https://github.com/WPO-Foundation/webpagetest-docs/blob/master/user/Private%20Instances/ec2_agents.md) +EC2 test agent AMIs can be found [here](https://github.com/catchpoint/WebPageTest.docs/blob/main/src/private-instances/ec2_agents.md) Connect to a Windows Test Agent: diff --git a/docs/Private Instances/MobileAgentRaspberryPi.md b/docs/Private Instances/MobileAgentRaspberryPi.md index 84fa2fea94..2bce61a26f 100644 --- a/docs/Private Instances/MobileAgentRaspberryPi.md +++ b/docs/Private Instances/MobileAgentRaspberryPi.md @@ -185,7 +185,7 @@ SUBSYSTEM=="usb", ATTR{idVendor}=="2b4c", MODE="0666", GROUP="plugdev", OWNER="< By far, the easiest way to get the code and keep it up to date is to clone the WebPageTest github repository. 1. ```cd ~``` -2. ```git clone https://github.com/WPO-Foundation/webpagetest.git webpagetest``` +2. ```git clone https://github.com/catchpoint/WebPageTest.git webpagetest``` 3. Test to make sure the python dependencies are working - ```cd webpagetest/agent/js/lib/video``` - ```python visualmetrics.py --check``` diff --git a/docs/adr/0004-adopt-laravel.md b/docs/adr/0004-adopt-laravel.md index 518dc206e5..0a03a4af7a 100644 --- a/docs/adr/0004-adopt-laravel.md +++ b/docs/adr/0004-adopt-laravel.md @@ -80,7 +80,7 @@ In phase 3 we convert each of the old entry points from `/wpt` to Laravel contro ### Views -In phase 1 we adopt the Blade templating engine. This is already [under way](https://github.com/WPO-Foundation/webpagetest/pull/2228) and the templates live in `www/resources` +In phase 1 we adopt the Blade templating engine. This is already [under way](https://github.com/catchpoint/WebPageTest/pull/2228) and the templates live in `www/resources` In the same phase we convert the prior template work from `www/templates` (which has API similar to Blade) to Blade, so we avoid having things like three competing footers. diff --git a/tests/CPClientTest.php b/tests/CPClientTest.php index 3c6f838301..da64979c46 100644 --- a/tests/CPClientTest.php +++ b/tests/CPClientTest.php @@ -275,34 +275,40 @@ public function testRevokeTokenBadResponse(): void public function testGetUser(): void { - $handler = $this->createMockResponse(200, '{ - "data": { - "userIdentity": { - "id": 12345, - "activeContact": { - "id": 263425, - "firstName": "Alice", - "lastName": "Bob", - "email": "alicebob@catchpoint.com", - "isWptPaidUser": true, - "isWptAccountVerified": true, - "companyName": null - }, - "levelSummary": { - "levelId": 3, - "isWptEnterpriseClient": false + $handler = $this->createMockResponse( + 200, + '{ + "data": { + "userIdentity": { + "id": 12345, + "activeContact": { + "id": 263425, + "firstName": "Alice", + "lastName": "Bob", + "email": "alicebob@catchpoint.com", + "isWptPaidUser": true, + "isWptAccountVerified": true, + "companyName": null + }, + "levelSummary": { + "levelId": 3, + "isWptEnterpriseClient": false + } + }, + "wptCustomer": { + "remainingRuns": 300, + "monthlyRuns": 3000, + "subscriptionId": "518235", + "planRenewalDate": "2125-12-25", + "status": "ACTIVE", + "vatNumber": null + }, + "wptIsPreviewEnabled": { + "enabled": false + } } - }, - "wptCustomer": { - "remainingRuns": 300, - "monthlyRuns": 3000, - "subscriptionId": "518235", - "planRenewalDate": "2125-12-25", - "status": "ACTIVE", - "vatNumber": null - } - } - }'); + }' + ); $host = "http://webpagetest.org"; $client = new CPClient($host, array( 'auth_client_options' => [ @@ -513,18 +519,18 @@ public function testGetWptPlans(): void } }'); - $host = "http://webpagetest.org"; - $client = new CPClient($host, array( - 'auth_client_options' => [ - 'client_id' => '123', - 'client_secret' => '345', - 'grant_type' => 'these are good to have', - 'handler' => $handler - ] - )); + $host = "http://webpagetest.org"; + $client = new CPClient($host, array( + 'auth_client_options' => [ + 'client_id' => '123', + 'client_secret' => '345', + 'grant_type' => 'these are good to have', + 'handler' => $handler + ] + )); - $plans = $client->getWptPlans(); - $this->assertEquals(3, count($plans)); + $plans = $client->getWptPlans(); + $this->assertEquals(3, count($plans)); } diff --git a/tests/RequestContextTest.php b/tests/RequestContextTest.php index 3bd3c3b48e..24e010a5f5 100644 --- a/tests/RequestContextTest.php +++ b/tests/RequestContextTest.php @@ -36,6 +36,6 @@ public function testSetGetClient(): void $client = new CPClient($host); $request = new RequestContext($global_req); $request->setClient($client); - $this->assertEquals($host, $request->getClient()->host); + $this->assertEquals($host, $request->getClient()->getHost()); } } diff --git a/www/assets/css/account.css b/www/assets/css/account.css index 6c511f1d79..0e7ffe8d97 100644 --- a/www/assets/css/account.css +++ b/www/assets/css/account.css @@ -181,6 +181,10 @@ body.theme-b { content: ":"; } +.breadcrumbs { + margin-top: 1rem; +} + .billing-history { display: block; padding-top: 2em; @@ -663,13 +667,13 @@ body.theme-b { /** * begin signup step 2 */ - .signup-flow-layout * { box-sizing: border-box; } .signup-flow-layout body { display: block; + background-color: #141e33; } .signup-flow-layout header { @@ -682,6 +686,18 @@ body.theme-b { padding-bottom: 1.5rem; } + +.signup-flow-layout header ol { + height: auto; + max-height: 4.5rem; + padding-left: 0; + display: flex; + justify-content: space-around; + align-items: center; + margin: 0; + padding-right: 1.5rem; +} + .signup-flow-layout header ol { padding-left: 0; display: flex; @@ -700,9 +716,18 @@ body.theme-b { font-weight: 700; } +.signup-flow-layout header ol, +.signup-flow-layout header .free-plan { + height: auto; + max-height: 4.5rem; + margin-top: 1rem; + margin-bottom: 1rem; + padding-right: 1.5rem; +} + + @media (min-width: 37.5rem) { .signup-flow-layout header { - padding-left: 30px; display: flex; justify-content: flex-start; } @@ -713,16 +738,33 @@ body.theme-b { margin: 1em 0; } - .signup-flow-layout header ol { + .signup-flow-layout header ol, + .signup-flow-layout header .free-plan { margin-left: 0; + margin-top: 0rem; + margin-bottom: 1rem; } +} +@media (min-width: 50em) { + .signup-flow-layout header ol, .signup-flow-layout header .free-plan { - margin-left: 0; + padding-right: 3rem; } } -@media (min-width: 86.25rem) { +@media (min-width: 86em) { + + .signup-flow-layout header ol, + .signup-flow-layout header .free-plan { + margin: 0; + position: relative; + height: 6rem; + max-height: 6rem; + top: 0.75rem; + padding-right: 1rem; + } + .signup-flow-layout header ol { margin-left: calc(50vw - 43.4375rem); } @@ -927,16 +969,11 @@ a.button { /* * End signup step 2 */ -.signup-flow-layout wpt-header, -.signup-flow-layout header { - background: #141e33; -} -.signup-flow-layout header { - padding-left: 0; - margin-bottom: 0; +.signup-flow-layout wpt-header { + background-color: #141e33; } + .signup-flow-layout header { - padding-left: 0; margin-bottom: 0; } @@ -945,13 +982,6 @@ a.button { padding-bottom: 1.5rem; } -.signup-flow-layout header ol { - padding-left: 0; - display: flex; - justify-content: space-around; - align-items: center; -} - .signup-flow-layout header li { margin-left: 40px; color: #d0d0d0; @@ -976,7 +1006,6 @@ a.button { @media (min-width: 600px) { .signup-flow-layout header { - padding-left: 30px; display: flex; justify-content: flex-start; } diff --git a/www/assets/css/pagestyle2.css b/www/assets/css/pagestyle2.css index 951f7a8130..1eb7a3347e 100644 --- a/www/assets/css/pagestyle2.css +++ b/www/assets/css/pagestyle2.css @@ -5158,13 +5158,14 @@ label.test_preset_profile { #simplemodal-overlay { background-color: #000; + z-index: 9999999 !important; } #simplemodal-container { background-color: #fff !important; padding: 5vh 5vw; position: fixed; - z-index: 9999999 !important; + z-index: 99999999 !important; height: 80vh !important; width: 80vw !important; left: 5vw !important; @@ -5175,6 +5176,85 @@ label.test_preset_profile { border-radius: 1em; } +#new-portal-dialog-container { + height: 312px !important; + max-height: 600px; + min-width: 400px; + width: 50vw !important; + max-width: 600px; + background-color: #fff !important; + padding: 20px; + position: fixed; + z-index: 99999999 !important; + overflow: auto !important; + border-radius: 10px; +} + +#new-portal-dialog { + display: flex; + flex-direction: column; + gap: 2em; + height: 100%; +} + +#new-portal-dialog .dialog-title { + color: #111; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + font-weight: 700; +} + +#new-portal-dialog .dialog-body { + color: #111; + display: flex; + flex-direction: column; + flex: 1; +} + +#new-portal-dialog .dialog-footer { + display: flex; + justify-content: flex-end; +} + +#new-portal-dialog .dialog-close-btn { + font-size: 1.4rem; + width: 1.4em; + height: 1.4em; + line-height: 1; + position: relative; + border: none; +} + +#new-portal-dialog .simplemodal-close { + border: none; + cursor: pointer; + background: transparent; + margin: 0; + font-size: 1.4rem; + width: 1.4em; + height: 1.4em; + line-height: 1; + text-indent: -999px; +} + +#new-portal-dialog .simplemodal-close:before, +#new-portal-dialog .simplemodal-close:after { + content: ""; + height: 1em; + width: 0.1em; + top: 0.2em; + left: 0.65em; + background: #777; + position: absolute; + transform: rotate(-45deg); +} + +#new-portal-dialog .simplemodal-close:after { + transform: rotate(45deg); +} + #simplemodal-container #advanced { background-color: #fff !important; color: #111 !important; diff --git a/www/assets/css/wpt-header.css b/www/assets/css/wpt-header.css index 26353601d4..f96ad12faa 100644 --- a/www/assets/css/wpt-header.css +++ b/www/assets/css/wpt-header.css @@ -87,23 +87,32 @@ wpt-header a { text-decoration: none; } -wpt-header .wptheader_logo { - flex: 1 1 75%; - height: 5rem; - max-height: 5rem; +wpt-header .wptheader_logo_container > p { + margin: 0; +} + +wpt-header .wptheader_logo_container { + position: relative; + flex: 1 1 50%; + height: 4.5rem; + max-height: 4.5rem; display: flex; box-sizing: border-box; align-content: center; - padding: 1em 0 1em 1.5rem; + align-items: center; background: none; - line-height: 3rem; font-weight: 300; font-size: 0.9em; margin: 0; + padding-left: 1.5rem; } wpt-header .wptheader_logo a { color: var(--wpt-header-text); } + +wpt-header .wptheader_logo a.pill { + padding: 0.5em 1em; +} wpt-header .wptheader_logo a:hover, wpt-header .wptheader_logo a:focus { text-decoration: underline; @@ -131,7 +140,7 @@ wpt-header .wptheader_logo a:first-child:after { cp-header a { padding-left: 3rem; } - wpt-header .wptheader_logo { + wpt-header .wptheader_logo_container { padding-left: 3rem; } } @@ -147,10 +156,10 @@ wpt-header .wptheader_menu { wpt-header .wptheader_menubtn { flex: 0 0 25%; - max-width: 5rem; + max-width: 4.5rem; padding: 1em 0; - height: 5rem; - max-height: 5rem; + height: 4.5rem; + max-height: 4.5rem; box-sizing: border-box; color: var(--wpt-header-text); border: 0; @@ -180,13 +189,13 @@ wpt-header nav { display: block; background: #141e33; color: #fff; - top: calc(5rem + 1px); + top: calc(4.5rem + 1px); position: absolute; width: 90%; right: 0; z-index: 1000; box-shadow: -5px 2px 5px rgba(0, 0, 0, 0.2); - min-height: calc(100vh - 5rem + 4px); + min-height: calc(100vh - 4.5rem + 4px); /* box-shadow: none; */ } @@ -243,8 +252,8 @@ wpt-header .wptheader_nav_menu_content { wpt-header .wptheader_acct { display: flex; - margin: 1rem; - padding: 2rem 1rem 2rem 2rem; + margin: 0 1rem; + padding: 0 1rem 0 2rem; background: var(--wpt-user-icon); } @@ -414,6 +423,20 @@ wpt-header .wptheader_nav_menu details[open] summary span:after { border-top-color: #101623; } +wpt-header #new_experience { + margin-left: 2rem; + background-color: #8348C7; + font-weight: normal; + cursor: pointer; +} + +wpt-header #new_experience:hover { + margin-left: 2rem; + background-color: #542985; + font-weight: normal; + cursor: pointer; +} + @media (min-width: 86em) { wpt-header { z-index: 999999; @@ -463,7 +486,7 @@ wpt-header .wptheader_nav_menu details[open] summary span:after { } wpt-header nav { position: relative; - top: auto; + top: 0.75rem; display: flex !important; flex: 1 1 60%; width: auto; @@ -520,19 +543,18 @@ wpt-header .wptheader_nav_menu details[open] summary span:after { overflow: visible; align-content: center; justify-content: space-between; - padding: 0 2vw; max-width: 1400px; margin: 0 auto -6rem; height: 6rem; + margin-top: -1.5rem; } - wpt-header .wptheader_logo { + wpt-header .wptheader_logo_container { flex: 1 1 20%; + top: 0.75rem; height: auto; - max-height: none; - padding: 0; + max-height: 6rem; background: none; - padding-left: 3vw; - line-height: 6rem; + padding-left: 1rem; } wpt-header .wptheader_nav { justify-content: space-between; @@ -590,8 +612,8 @@ wpt-header .wptheader_nav_menu details[open] summary span:after { wpt-header header { padding: 0; } - wpt-header .wptheader_logo { - padding-left: 0; + wpt-header .wptheader_logo_container { + padding-left: 1rem; } } diff --git a/www/assets/js/wpt-header.js b/www/assets/js/wpt-header.js index b140e5d46a..6c9e21a23d 100644 --- a/www/assets/js/wpt-header.js +++ b/www/assets/js/wpt-header.js @@ -15,7 +15,7 @@ class WptHeader extends HTMLElement { } _init() { this.menubtn = this.querySelector(".wptheader_menubtn"); - this.menu = this.menubtn.closest("details"); + this.menu = this.menubtn ? this.menubtn.closest("details") : null; this.details = this.querySelectorAll("nav details"); let that = this; this.headerLayoutChange = getComputedStyle( @@ -60,6 +60,10 @@ class WptHeader extends HTMLElement { return getComputedStyle(this.menubtn).display; } updateMenuAttrs(e) { + if (!this.menu) { + return; + } + if (e.matches) { this.menu.open = true; } else { @@ -71,3 +75,14 @@ class WptHeader extends HTMLElement { if ("customElements" in window) { customElements.define("wpt-header", WptHeader); } + +function OpenNewPortalDialog() { + $("#new-portal-dialog").modal({ + opacity: 80, + overlayClose: true, + containerId: 'new-portal-dialog-container', + minWidth: 500, + maxWidth: 500 + }); + return false; +}; diff --git a/www/common.inc b/www/common.inc index 5853633155..ca891d11ce 100644 --- a/www/common.inc +++ b/www/common.inc @@ -565,3 +565,7 @@ if (is_file(SETTINGS_PATH . '/custom_common.inc.php')) { } require_once INCLUDES_PATH . '/experiments/user_access.inc'; + +$request_context->setReadOnly( + !is_null($request_context->getUser()) && $request_context->getUser() && $request_context->getUser()->newPortalExperience() +); diff --git a/www/common_lib.inc b/www/common_lib.inc index ca78b3b829..cb0d57e715 100644 --- a/www/common_lib.inc +++ b/www/common_lib.inc @@ -4037,6 +4037,19 @@ function ReportSaaSTest($test_json, $node_id, $test_id) } } +/** + * Handle redirect in read-only mode + */ +function RedirectIfReadOnly() +{ + global $request_context; + + if (Util::getSetting('cp_portal_redirect') && Util::getSetting('cp_portal_url') && $request_context->isReadOnly()) { + header('Location: ' . Util::getSetting('cp_portal_url')); + exit(); + } +} + if (!function_exists('str_contains')) { function str_contains($haystack, $needle) { diff --git a/www/cpauth/logout.php b/www/cpauth/logout.php index 7c2841be7f..d2cd7b9781 100644 --- a/www/cpauth/logout.php +++ b/www/cpauth/logout.php @@ -21,18 +21,17 @@ $cp_access_token_cookie_name = Util::getCookieName(CPOauth::$cp_access_token_cookie_key); $cp_refresh_token_cookie_name = Util::getCookieName(CPOauth::$cp_refresh_token_cookie_key); - $request_method = $request_context->getRequestMethod(); $protocol = $request_context->getUrlProtocol(); $host = Util::getSetting('host'); $redirect_uri = "{$protocol}://{$host}"; - if ($request_method === 'POST') { + try { $access_token = $request_context->getUser()->getAccessToken(); if (!is_null($access_token)) { $request_context->getClient()->revokeToken($access_token); } - + } finally { setcookie($cp_access_token_cookie_name, "", time() - 3600, "/", $host); setcookie($cp_refresh_token_cookie_name, "", time() - 3600, "/", $host); diff --git a/www/details.php b/www/details.php index c5078b9652..567e101c3c 100644 --- a/www/details.php +++ b/www/details.php @@ -70,26 +70,18 @@ function createForm($formName, $btnText, $id, $owner, $secret) $tab = 'Test Result'; $subtab = 'Details'; include 'header.inc'; - ?>
- -
-

Requests Details

Use this page to explore the metric timings and request waterfall for any run of your test.

- -
-
- Page Performance Metrics (Run ' . $run . ($cached ? ', Repeat View' : '') . ')'; @@ -123,7 +115,6 @@ function createForm($formName, $btnText, $id, $owner, $secret) } ?> - disableColumns(array( @@ -138,6 +129,7 @@ function createForm($formName, $btnText, $id, $owner, $secret) )); echo $htmlTable->create(true); ?> +
+ isReadOnly()): ?> +
+ + + '; @@ -420,8 +417,6 @@ function handleHash() { handleRequestHash(); } - - // init existing snippets $(document).ready(function() { initDetailsTable($(document)); @@ -439,5 +434,4 @@ function handleHash() { - \ No newline at end of file diff --git a/www/enable_portal.php b/www/enable_portal.php new file mode 100644 index 0000000000..12aee78d93 --- /dev/null +++ b/www/enable_portal.php @@ -0,0 +1,42 @@ +getUser(); +if (is_null($user)) { + header("Location: /"); + return; +} + +if ($user->isAnon()) { + header("Location: /"); + return; +} + +if ($user->isFree() && !Util::getSetting('cp_portal_enable_free')) { + header("Location: /"); + return; +} + +if ($user->isPaid() && !Util::getSetting('cp_portal_enable_pro')) { + header("Location: /"); + return; +} + +$value = isset($req_value) ? (bool) $req_value : true; +$client = $request_context->getClient(); +$portal_enabled = $client->enablePortalPreview($value); +$location = $portal_enabled ? Util::getSetting('cp_portal_url') : '/'; + +header('Location: ' . $location); +return; diff --git a/www/experiments.php b/www/experiments.php index 8b9d9f5122..5c032c3b75 100644 --- a/www/experiments.php +++ b/www/experiments.php @@ -18,11 +18,14 @@ require_once INCLUDES_PATH . '/include/RunResultHtmlTable.php'; require_once INCLUDES_PATH . '/include/TestResultsHtmlTables.php'; +$isReadOnly = $request_context->isReadOnly(); + // if this is an experiment itself, we don't want to offer opps on it, so we redirect to the source test's opps page. if ($experiment && isset($experimentOriginalExperimentsHref)) { header('Location: ' . $experimentOriginalExperimentsHref); } + $breakdown = array(); $testComplete = true; $status = GetTestStatus($id, false); @@ -43,6 +46,7 @@ $page_description = "Website performance test result$testLabel."; ?> + @@ -60,29 +64,30 @@ margin-right: 0.4em; } - + + + - + + + require_once 'head.inc'; + ?> - - "> + -
+
@@ -112,35 +117,29 @@ ?> -
- -
-
-

Opportunities & Experiments New

-

WebPageTest helps identify opportunities to improve a site's experience. Select one or more No-Code Experiments below and submit to test their impact.

-
- - - -
+
+
+
+

Opportunities & Experiments New

+

WebPageTest helps identify opportunities to improve a site's experience. Select one or more No-Code Experiments below and submit to test their impact.

+
+
getRequests(); - + $testStepResult = TestStepResult::fromFiles($testInfo, $run, $cached, $step); + $requests = $testStepResult->getRequests(); - include INCLUDES_PATH . '/experiments/common.inc'; + include INCLUDES_PATH . '/experiments/common.inc'; + include INCLUDES_PATH . '/experiments/summary.inc'; - include INCLUDES_PATH . '/experiments/summary.inc'; if ($experiment) { $moreExperimentsLink = false; include INCLUDES_PATH . '/experiments/meta.inc'; } ?> - '; } if ($exp->expvar) { - if ($experimentEnabled) { + if ($isReadOnly) { + $out .= '
'; + } else if ($experimentEnabled) { $out .= <<
@@ -323,7 +323,9 @@ function observationHTML($parts) } } } elseif ($exp->expvar && !$exp->expval && $exp->expfields) { - if ($experimentEnabled) { + if ($isReadOnly) { + $out .= '
'; + } else if ($experimentEnabled) { $out .= <<
@@ -349,7 +351,9 @@ function observationHTML($parts) $out .= $upgradeLink; } } elseif ($exp->expvar && !$exp->expval && $textinput) { - if ($experimentEnabled) { + if ($isReadOnly) { + $out .= '
'; + } else if ($experimentEnabled) { $placeholderEncodedVal = htmlentities(''); $textinputvalue = $exp->textinputvalue ? $exp->textinputvalue : ""; $fullscreenfocus = $exp->fullscreenfocus ? "true" : "false"; @@ -364,7 +368,9 @@ function observationHTML($parts) $out .= $upgradeLink; } } elseif ($exp->expvar && !$exp->expval) { - if ($experimentEnabled) { + if ($isReadOnly) { + $out .= '
'; + } else if ($experimentEnabled) { $out .= <<
@@ -386,12 +392,6 @@ function observationHTML($parts) return $out; } - - - - - - // write out the observations HTML foreach ($assessment as $key => $cat) { $grade = $cat["grade"]; @@ -402,37 +402,34 @@ function observationHTML($parts) $bad = $cat["num_recommended"]; $good = $opps - $bad; if ($key === "Custom") { + if (!$isReadOnly) { + echo << + +

Create Experiments

+

${sentiment} ${summary}

+
+
+
    + EOT; + foreach ($cat["opportunities"] as $opportunity) { + echo observationHTML($opportunity); + } + echo '
'; + } + } else { echo << - -

Create Experiments

+
+

Is it ${key}?

${sentiment} ${summary}

-
+
+

WebPageTest ran ${opps} diagnostic checks related to this category and found ${bad} opportunities.

    - EOT; foreach ($cat["opportunities"] as $opportunity) { echo observationHTML($opportunity); } - echo '
'; - } else { - echo << -

Is it ${key}?

-

${sentiment} ${summary}

-
-
-

WebPageTest ran ${opps} diagnostic checks related to this category and found ${bad} opportunities.

-
    - - EOT; - - - foreach ($cat["opportunities"] as $opportunity) { - echo observationHTML($opportunity); - } echo '
'; } } @@ -440,114 +437,125 @@ function observationHTML($parts) $numRuns = $test['test']['runs']; $fvonly = $test['testinfo']['fvonly']; + if (!$isReadOnly) { + ?> +
+
+

+ +

+

+ +

+
+ + + + +
+
+ - echo '
-

-

-
'; +
+
+
- echo ''; + - echo ''; - echo "\n
\n"; - } - ?> + - + - - - - - - + - + } + setTimeout('UpdateStatus()', 15000); + + - + + diff --git a/www/footer.inc b/www/footer.inc index ccbeb87402..b99cd043b7 100644 --- a/www/footer.inc +++ b/www/footer.inc @@ -16,7 +16,7 @@ '; include("testinfo_command-bar.inc"); diff --git a/www/home.php b/www/home.php index d6e93e11ef..30ef1b457a 100644 --- a/www/home.php +++ b/www/home.php @@ -10,6 +10,8 @@ use WebPageTest\Util\SettingsFileReader; use WebPageTest\Util\Timers; +RedirectIfReadOnly(); + $Timers = new Timers(); // see if we are overriding the max runs $max_runs = GetSetting('maxruns', 9); @@ -76,14 +78,21 @@ $Timers->endTimer('loc'); $Timers->startTimer('status'); + // Is the user a logged in and paid user? -$is_paid = isset($request_context) && !is_null($request_context->getUser()) && $request_context->getUser()->isPaid(); +$user = isset($request_context) && !is_null($request_context->getUser()) ? $request_context->getUser() : null; +$is_paid = !is_null($user) && $user->isPaid(); +$is_free = !is_null($user) && $user->isFree(); +$is_anon = is_null($user) || $user->isAnon(); + $is_logged_in = Util::getSetting('cp_auth') && (!is_null($request_context->getClient()) && $request_context->getClient()->isAuthenticated()); -$remaining_runs = (isset($request_context) && !is_null($request_context->getUser())) ? $request_context->getUser()->getRemainingRuns() : 300; +$remaining_runs = !is_null($user) ? $user->getRemainingRuns() : 300; $hasNoRunsLeft = $is_logged_in ? (int)$remaining_runs <= 0 : false; + $Timers->endTimer('status'); header('Server-Timing: ' . $Timers->getTimers()); + ?> @@ -119,14 +128,14 @@
+ ?>
+ ?>
- +
@@ -288,17 +297,18 @@ let lhSimpleFields = document.querySelector('[for=lighthouse-simple]'); let ccSimpleField = document.querySelector('[for=inc-cc-simple]'); let lhSimpleCheck = lhSimpleFields.querySelector('input'); - function enableDisableLHSimple(){ - let checkedPreset = simplePresets.querySelector('input[type=radio]:checked'); - if(checkedPreset.parentElement.querySelector('img[alt*="chrome"]') || checkedPreset.parentElement.querySelector('img[alt*="edge"]')){ - ccSimpleField.style.display = "block"; - lhSimpleFields.style.display = "block"; - lhSimpleCheck.disabled = false; - } else { - ccSimpleField.style.display = "none"; - lhSimpleFields.style.display = "none"; - lhSimpleCheck.disabled = true; - } + + function enableDisableLHSimple() { + let checkedPreset = simplePresets.querySelector('input[type=radio]:checked'); + if (checkedPreset.parentElement.querySelector('img[alt*="chrome"]') || checkedPreset.parentElement.querySelector('img[alt*="edge"]')) { + ccSimpleField.style.display = "block"; + lhSimpleFields.style.display = "block"; + lhSimpleCheck.disabled = false; + } else { + ccSimpleField.style.display = "none"; + lhSimpleFields.style.display = "none"; + lhSimpleCheck.disabled = true; + } } enableDisableLHSimple(); simplePresets.addEventListener("click", enableDisableLHSimple); @@ -402,14 +412,12 @@ function enableDisableLHSimple(){
-
Runs Left | Upgrade > -
@@ -549,7 +557,7 @@ function enableDisableLHSimple(){ ?> + } ?> value="0">First View and Repeat View @@ -643,11 +651,11 @@ function enableDisableLHSimple(){ - +
  • What is checked: Checked to see if it is hosted on a known CDN (CNAME mapped to a known CDN network). 80% of the static resources need to be served from a CDN for the overall page to be considered using a CDN. The current list of known CDN's is - here. + here.
  • diff --git a/www/resources/views/partials/lighthouse/audititem.blade.php b/www/resources/views/partials/lighthouse/audititem.blade.php index 1a166a0a8b..30338d9980 100644 --- a/www/resources/views/partials/lighthouse/audititem.blade.php +++ b/www/resources/views/partials/lighthouse/audititem.blade.php @@ -4,7 +4,7 @@
    {!! md($audit->title) !!} - @if($audit->relevantExperiment) + @if($audit->relevantExperiment && !$is_read_only) @include('partials.lighthouse.auditExperiment') @endif
    diff --git a/www/settings/about.inc.sample b/www/settings/about.inc.sample index 9c5e202ae3..2e0abf0053 100644 --- a/www/settings/about.inc.sample +++ b/www/settings/about.inc.sample @@ -1,7 +1,7 @@

    About WebPageTest.org

    WebPageTest is a tool that was originally developed by AOL for use internally and was open-sourced in 2008 under a BSD license. -The platform is under active development by several companies and community contributors on GitHub. +The platform is under active development by several companies and community contributors on GitHub. The software is also packaged up periodically and available for download if you would like to run your own instance.

    diff --git a/www/src/CPClient.php b/www/src/CPClient.php index 2af60d8825..6703c2a8a7 100644 --- a/www/src/CPClient.php +++ b/www/src/CPClient.php @@ -45,6 +45,7 @@ class CPClient public ?string $client_id; public ?string $client_secret; private ?string $access_token; + private ?string $host; private $handler; // For unit tests public function __construct(string $host, array $options = []) @@ -101,6 +102,11 @@ public function isAuthenticated(): bool return !!$this->access_token; } + public function getHost(): ?string + { + return $this->host; + } + public function login(string $code, string $code_verifier, string $redirect_uri): AuthToken { if (is_null($this->client_id) || is_null($this->client_secret)) { @@ -217,7 +223,11 @@ public function getUser(): User 'planRenewalDate', 'nextBillingDate', 'status', - 'vatNumber' + 'vatNumber', + ]), + (new Query('wptIsPreviewEnabled')) + ->setSelectionSet([ + 'enabled' ]) ]); @@ -250,6 +260,8 @@ public function getUser(): User $user->setEnterpriseClient(!!$data['userIdentity']['levelSummary']['isWptEnterpriseClient']); $user->setVatNumber($data['wptCustomer']['vatNumber']); + $user->setNewPortalExperience($data['wptIsPreviewEnabled']['enabled']); + return $user; } catch (GuzzleException $e) { if ($e->getCode() == 401 || $e->getCode() == 403) { @@ -309,19 +321,19 @@ public function getFullWptPlanSet(): PlanListSet return new Plan($options); }, $results->getData()['wptPlan'] ?? []); - $current_plans = array_filter($all_plans, function (Plan $plan) { - /** This is a bit of a hack for now. These are our approved plans for new - * customers to be able to use. We will better handle this from the backend - * */ - return strtolower($plan->getId()) == 'ap5' || - strtolower($plan->getId()) == 'ap6' || - strtolower($plan->getId()) == 'ap7' || - strtolower($plan->getId()) == 'ap8' || - strtolower($plan->getId()) == 'mp5' || - strtolower($plan->getId()) == 'mp6' || - strtolower($plan->getId()) == 'mp7' || - strtolower($plan->getId()) == 'mp8'; - }); + $current_plans = array_filter($all_plans, function (Plan $plan) { + /** This is a bit of a hack for now. These are our approved plans for new + * customers to be able to use. We will better handle this from the backend + * */ + return strtolower($plan->getId()) == 'ap5' || + strtolower($plan->getId()) == 'ap6' || + strtolower($plan->getId()) == 'ap7' || + strtolower($plan->getId()) == 'ap8' || + strtolower($plan->getId()) == 'mp5' || + strtolower($plan->getId()) == 'mp6' || + strtolower($plan->getId()) == 'mp7' || + strtolower($plan->getId()) == 'mp8'; + }); $set = new PlanListSet(); $set->setAllPlans(new PlanList(...$all_plans)); $set->setCurrentPlans(new PlanList(...$current_plans)); @@ -1063,21 +1075,46 @@ public function updatePlan(string $subscription_id, string $next_plan_handle, bo public function updatePaymentMethod(string $token, ShippingAddress $address): bool { $gql = (new Mutation('wptUpdateSubscriptionPayment')) - ->setVariables([ - new Variable('paymentToken', 'String', true), - new Variable('shippingAddress', 'ChargifyAddressInputType', true) - ]) - ->setArguments([ - 'paymentToken' => '$paymentToken', - 'shippingAddress' => '$shippingAddress' - ]); + ->setVariables([ + new Variable('paymentToken', 'String', true), + new Variable('shippingAddress', 'ChargifyAddressInputType', true) + ]) + ->setArguments([ + 'paymentToken' => '$paymentToken', + 'shippingAddress' => '$shippingAddress' + ]); $variables = [ - 'paymentToken' => $token, - 'shippingAddress' => $address->toArray() + 'paymentToken' => $token, + 'shippingAddress' => $address->toArray() ]; $results = $this->graphql_client->runQuery($gql, true, $variables); return $results->getData()['wptUpdateSubscriptionPayment']; } + + public function enablePortalPreview(bool $value) + { + try { + $gql = (new Mutation('wptPreviewEnable')) + ->setVariables([ + new Variable('wptPreviewEnable', 'WptPreviewEnableInputType', true), + ]) + ->setArguments([ + 'wptPreviewEnableRequest' => '$wptPreviewEnable' + ]) + ->setSelectionSet([ + 'enabled' + ]); + + $variables = [ + 'wptPreviewEnable' => ['enable' => $value] + ]; + + $results = $this->graphql_client->runQuery($gql, true, $variables); + return $results->getData()['wptPreviewEnable']['enabled']; + } catch (BaseException $e) { + return false; + } + } } diff --git a/www/src/RequestContext.php b/www/src/RequestContext.php index d550854d33..f8f19b79b4 100644 --- a/www/src/RequestContext.php +++ b/www/src/RequestContext.php @@ -22,6 +22,7 @@ class RequestContext private string $request_method; private string $request_uri; private string $host; + private bool $read_only; private ?BannerMessageManager $banner_message_manager; // Should use an enum, TODO private string $environment; @@ -50,6 +51,7 @@ public function __construct(array $global_request, array $server = [], array $op $this->environment = Environment::$Production; $this->api_key_in_use = null; + $this->read_only = false; } public function getRaw(): array @@ -153,6 +155,16 @@ public function getEnvironment(): string return $this->environment; } + public function isReadOnly(): bool + { + return $this->read_only; + } + + public function setReadOnly(bool $value) + { + $this->read_only = $value; + } + /** * This returns an API key if one is in use, if not, it returns an empty string * diff --git a/www/src/User.php b/www/src/User.php index 8bf27cda3d..af00f7fd44 100644 --- a/www/src/User.php +++ b/www/src/User.php @@ -13,10 +13,13 @@ class User private bool $is_admin; private ?string $owner_id; private ?string $access_token; + private ?string $refresh_token; private ?int $user_id; private ?int $contact_id; private bool $is_paid_cp_client; + private bool $new_portal_experience; private bool $is_verified; + private int $user_priority; private bool $is_wpt_enterprise_client; private int $remaining_runs; private int $monthly_runs; @@ -38,9 +41,11 @@ public function __construct() $this->is_admin = false; $this->owner_id = "2445"; // owner id of 2445 was for unpaid users $this->access_token = null; + $this->refresh_token = null; $this->user_id = null; $this->contact_id = null; $this->is_paid_cp_client = false; + $this->new_portal_experience = false; $this->is_verified = false; $this->user_priority = 9; //default to lowest possible priority $this->is_wpt_enterprise_client = false; @@ -89,6 +94,23 @@ public function isPaid(): bool ($this->payment_status == 'ACTIVE' || $this->isPendingCancelation()); } + public function newPortalExperience(): bool + { + if ( + ($this->isPaid() && Util::getSetting('cp_portal_enable_pro')) || + ($this->isFree() && Util::getSetting('cp_portal_enable_free')) + ) { + return $this->new_portal_experience; + } + + return false; + } + + public function setNewPortalExperience(bool $value) + { + $this->new_portal_experience = $value; + } + public function isFree(): bool { return !$this->isPaid() && !$this->isAnon(); diff --git a/www/templates/account/billing/update-payment-confirm-address.php b/www/templates/account/billing/update-payment-confirm-address.php index 6621d218c6..d079476de8 100644 --- a/www/templates/account/billing/update-payment-confirm-address.php +++ b/www/templates/account/billing/update-payment-confirm-address.php @@ -1,14 +1,15 @@
    + +
    - +

    Edit Billing Information

    -

    Edit Billing Information

    @@ -33,8 +34,8 @@ @@ -46,8 +47,8 @@ +
    @@ -80,21 +81,21 @@ -
    + \ No newline at end of file diff --git a/www/templates/account/plans/upgrade-plan.php b/www/templates/account/plans/upgrade-plan.php index 93ed9519d5..021b43c053 100644 --- a/www/templates/account/plans/upgrade-plan.php +++ b/www/templates/account/plans/upgrade-plan.php @@ -8,7 +8,7 @@

    Update Plan

    - Contact Support + Contact Support
    @@ -103,7 +103,7 @@
    -
    Limited-time
    special price
    +
    Limited-time
    special price
    Expert
    Starting from 10M pageviews (RUM) + 30K runs/month @@ -253,21 +253,21 @@ - - Traceroute - - - Yes - - - - Yes - - - - Yes - - + + Traceroute + + + Yes + + + + Yes + + + + Yes + + diff --git a/www/templates/layouts/includes/wpt-header.php b/www/templates/layouts/includes/wpt-header.php index 8af7f3b767..b14dc64ed1 100644 --- a/www/templates/layouts/includes/wpt-header.php +++ b/www/templates/layouts/includes/wpt-header.php @@ -48,6 +48,36 @@ function addTab($tabName, $tabUrl, $addClass = '') // login status $is_logged_in = Util::getSetting('cp_auth') && (!is_null($request_context)) && (!is_null($request_context->getClient()) && $request_context->getClient()->isAuthenticated()); +$user = !is_null($request_context) ? $request_context->getUser() : null; + +if (isset($request_context) && $request_context->isReadOnly()) { + +?> + + + + + + +isPaid() : false; +$is_free = !is_null($user) ? $user->isFree() : false; +$show_new_ui_activation_button = Util::getSetting('cp_portal_url') && ( + ($is_pro && Util::getSetting('cp_portal_enable_pro')) || ($is_free && Util::getSetting('cp_portal_enable_free')) +); ?> @@ -61,10 +91,47 @@ function addTab($tabName, $tabUrl, $addClass = '')
    - +
    + +

    + + + Enable New UI + + +

    + +
    Menu: @@ -107,19 +174,19 @@ function addTab($tabName, $tabUrl, $addClass = '')

    By Team

    - +

    By Use Case

    - +
    @@ -155,7 +222,7 @@ function addTab($tabName, $tabUrl, $addClass = '') - + @@ -167,22 +234,20 @@ function addTab($tabName, $tabUrl, $addClass = '')