diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f2fba4bc8..d5f4d20655 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -296,58 +296,3 @@ jobs: run: | diff $GENERATOR_OUTPUT_DIR_CI $GENERATOR_OUTPUT_DIR_VC \ || { echo "OpenAPI spec is out of date. Please regenerate via ./scripts/generate_openapi.sh"; exit 1; } - - e2e-tests: - # Disabling the E2E tests for now - if: false - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 - - - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4 - with: - node-version: "^20" - cache: yarn - cache-dependency-path: e2e_testing/yarn.lock - - - name: Install frontend dependencies - run: yarn install --immutable - - - name: Build frontend - run: NODE_ENV=production yarn build - - - name: Build exported components - run: NODE_ENV=production yarn workspace mit-learn build-exports - - - name: Build services - run: docker compose -f docker-compose-e2e-tests.yml build - - - name: Start services - run: docker compose -f docker-compose-e2e-tests.yml up nginx web --detach --wait - - - name: Apply test data - run: ./e2e_testing/scripts/apply-fixtures.sh - - - name: Install E2E test dependencies - working-directory: e2e_testing - run: yarn install --immutable - - - name: Install Playwright browsers - working-directory: e2e_testing - run: yarn playwright install --with-deps chromium - - - name: Run E2E tests - working-directory: e2e_testing - run: BASE_URL=http://localhost:8063 CI=true yarn test - - - name: Setup Pages - if: always() - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 - - - name: Upload artifact - if: always() - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4 - with: - name: playwright-report - path: e2e_testing/playwright-report diff --git a/.gitignore b/.gitignore index c103e2eaf6..4032c66543 100644 --- a/.gitignore +++ b/.gitignore @@ -130,12 +130,5 @@ github-pages/public # Storybook storybook-static/ -/e2e_testing/test-results/ -/e2e_testing/playwright-report/ -/e2e_testing/blob-report/ -/e2e_testing/playwright/.cache/ -!/e2e_testing/.env - /**/.yarn/cache -e2e_testing/.yarn/cache .swc diff --git a/README.md b/README.md index 4c2e992743..78b156c80c 100644 --- a/README.md +++ b/README.md @@ -251,42 +251,6 @@ Personal API keys only need read permission to Query. When creating a personal A Once these are set (and you've restarted the app), you should see events flowing into the PostHog dashboard. -## Exported Components - -A Javascript bundle of exported frontend components can be generated for use in external websites that have CORS allowance into a given instance of `mit-learn`. There are a few settings you might want to change in order to get the expected results. - -- `MITOL_AXIOS_WITH_CREDENTIALS` - This sets `withCredentials: true` when initializing the Axios API, which tells the end user's browser to send along any browser level cookies for the current domain when making CORS requests -- `MITOL_API_BASE_URL` - This sets the base url used for API requests, which will need to be set to a fully qualified url pointing to an instance of `mit-learn` (i.e. https://learn.mit.edu) in order for requests from the external site to reach the proper destination -- `CORS_ALLOWED_ORIGINS`, `CSRF_TRUSTED_ORIGINS` - On the instance of `mit-learn` that the externally hosted components will access via the API, the domains of any sites that need CORS access need to be here as a list of strings - -To build the bundle of exported components, run: - -``` -yarn workspace mit-learn build-exports -``` - -The bundle will build out to `frontends/mit-learn/build-exports/` - -### `initMitOpenDom` - -This function takes an argument of an `HTMLElement` with which `mit-learn` components will mount into. - -### `openAddToUserListDialog` - -This function opens a modal for adding a given `LearningResource` to a `UserList`, given the `readable_id` of the `LearningResource` object. Given a div with an ID of `mit-learn-components` and a button with the ID for `add-to-user-list-button`, you would use it in combination with `initMitOpenDom` like this: - -```javascript -import { initMitOpenDom, openAddToUserListDialog } from "mit-learn-components" - -$("#add-to-user-list-button").on("click", async (event) => { - event.preventDefault() - await initMitOpenDom($("#mit-learn-components")) - await openAddToUserListDialog("18.700+fall_2013") -}) -``` - -This is just an example, and you could input any `readable_id` to bring up a dialog to add any given `LearningResource` object to a `UserList`. - ## GitHub Pages Storybook Demos and documentation of reusable UI components in this repo are published as a [storybook](https://storybook.js.org/) at https://mitodl.github.io/mit-learn/. diff --git a/channels/views_test.py b/channels/views_test.py index 00c0334e7a..02a71ecd4f 100644 --- a/channels/views_test.py +++ b/channels/views_test.py @@ -187,7 +187,7 @@ def test_patch_channel_image(client, channel, attribute): os.path.dirname(__file__), # noqa: PTH120 "..", "frontends", - "mit-learn", + "main", "public", "images", "blank.png", diff --git a/config/static-app.conf b/config/static-app.conf deleted file mode 100644 index 8eedb30856..0000000000 --- a/config/static-app.conf +++ /dev/null @@ -1,10 +0,0 @@ -# This is the version used ONLY for e2e tests because we statically compile to production mode -server { - listen 8063 $APP_BASE_URL; - root /src/frontends/mit-learn/build; - - location / { - try_files /index.html =404; - } - -} diff --git a/docker-compose-e2e-tests.yml b/docker-compose-e2e-tests.yml deleted file mode 100644 index dd89564da5..0000000000 --- a/docker-compose-e2e-tests.yml +++ /dev/null @@ -1,94 +0,0 @@ -version: "3.7" - -name: mit-learn-e2e-tests - -services: - db: - image: postgres:12.20 - ports: - - 5432:5432 - environment: - - POSTGRES_PASSWORD=postgres - healthcheck: - test: ["CMD", "pg_isready", "-U", "postgres"] - interval: 5s - timeout: 5s - retries: 2 - - nginx: - image: nginx:1.27.1 - ports: - - 8063:8063 - links: - - web - volumes: - - ./config/nginx.conf:/etc/nginx/conf.d/web.conf - - ./config/static-app.conf:/etc/nginx/templates/static-app.template - - ./frontends/mit-learn/build:/src/frontends/mit-learn/build - env_file: - - path: ./env/shared.env - networks: - default: - aliases: - - "open.odl.local" - - "api.open.odl.local" - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8063"] - interval: 30s - timeout: 10s - retries: 5 - - build-frontend: - build: - context: ./frontends - environment: - - NODE_ENV=production - working_dir: /src - user: root - command: bash -c "yarn build" - volumes: - - .:/src - - yarn-cache:/home/mitodl/.cache/yarn - - web: - build: - context: . - environment: - DATABASE_URL: postgres://postgres:postgres@db:5432/e2e_postgres # pragma: allowlist secret - PORT: 8061 - env_file: env/ci.env - depends_on: - db: - condition: service_healthy - command: > # pragma: allowlist secret - bash -c "export PGPASSWORD=postgres - && dropdb --if-exists -h db -U postgres e2e_postgres - && createdb -h db -U postgres e2e_postgres - && python3 manage.py collectstatic --noinput --clear - && python3 manage.py migrate --noinput - && python3 manage.py loaddata e2e_testing/fixtures/*.json - && uwsgi uwsgi.ini --honour-stdin" - stdin_open: true - tty: true - ports: - - 8061:8061 - links: - - db - - e2e-tests: - build: - context: e2e_testing - environment: - - CI=true - - BASE_URL=http://open.odl.local:8063 - depends_on: - nginx: - condition: service_healthy - links: - - nginx - command: bash -c "yarn install && yarn test" - volumes: - - ./e2e_testing:/tests - -volumes: - yarn-cache: diff --git a/e2e_testing/.env b/e2e_testing/.env deleted file mode 100644 index f85fcfe57a..0000000000 --- a/e2e_testing/.env +++ /dev/null @@ -1,4 +0,0 @@ -BASE_URL=http://localhost:8063/ -# BASE_URL=http://nginx:8063/ -# BASE_URL=https://rc.learn.mit.edu/ -# BASE_URL=https://learn.mit.edu/ diff --git a/e2e_testing/.yarn/install-state.gz b/e2e_testing/.yarn/install-state.gz deleted file mode 100644 index 51822c5d47..0000000000 Binary files a/e2e_testing/.yarn/install-state.gz and /dev/null differ diff --git a/e2e_testing/Dockerfile b/e2e_testing/Dockerfile deleted file mode 100644 index bec62aa0b5..0000000000 --- a/e2e_testing/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM mcr.microsoft.com/playwright:v1.47.0-jammy - -COPY . /tests - -WORKDIR /tests - -ENV CI=false -ENV BASE_URL=http://localhost:8063/ - -RUN yarn install - -CMD ["yarn", "test"] diff --git a/e2e_testing/README.md b/e2e_testing/README.md deleted file mode 100644 index 72714f44eb..0000000000 --- a/e2e_testing/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# E2E Testing - -The E2E Tests bring the web front end and backing services under test and emulate a user interacting with the browser. - -They are designed to run in two modes: - -- _Pre-release_ - During CI the tests run against locally spun up services including an ephemeral database that includes the Django web service schema migrations plus any test fixture data for the tests to make assertions against. - -- _Post-release_ - A subset of the tests can be run against a live environment to sanity check deployments and confirm services are running as expected. These are intended to be non destructive with regard to the database and so should not make changes to data or be dependent on any pre-existing data (see Tag Annotations below). - -We are using [Playwright](https://playwright.dev/) as the testing framework. This provides browser instances augmented with Playwright's language API for selecting DOM elements, emulating user interactions and making assertions. - -## Testing a User's Perspective - -A primary benefit of E2E Testing (also Acceptance Testing in this context) is that the tests have zero or very limited visibility of the internals of the system under test. This yields a focus on the user facing feature set irrespective of the code, facilitating refactor without test rewrite and producing a test suite styled around the product requirements and a test output that describes the product's specification. - -The tests then should interpret the rendered UI as would a user or an assistive technology. Historically source code would be annotated with HTML attributes for the tests to select on, or tests would make use of DOM XPaths or CSS selector paths. These approaches should be avoided as they incur a reliance on the implementation detail, can be brittle and do not reflect a user's view of the system. Playwright's best practices include a recommendation to [test user-visible behavior](https://playwright.dev/docs/best-practices#test-user-visible-behavior) and an element [Locator](https://playwright.dev/docs/locators) preference to select on accessibility attributes and textual content. Where practical, this approach should be followed. - -## Development - -Playwright provides a [UI workbench](https://playwright.dev/docs/test-ui-mode) for running and debugging tests during development. This can be started from the `e2e_testing` directory with: - -```bash -yarn start -``` - -For headless testing from the command line and on CI, we can run the tests with: - -```bash -yarn test -``` - -To target specific environments, set `BASE_URL` on the environment, e.g: - -```bash -BASE_URL=https://learn.mit.edu/ yarn test -``` - -NPM scripts are provided for our RC and Production environments: - -```bash -yarn test:rc -yarn test:production -``` - -A Docker Compose configuration at [docker-compose-e2e-tests.yml](../docker-compose-e2e-tests.yml) provides the minimal run configuration for starting services needed for testing, the Postgres database, the backend web service and our nginx reverse proxy. - -Services can be started with: - -```bash -docker compose -f docker-compose-e2e-tests.yml up web db nginx -``` - -The tests themselves are also containerized so the following command will start all services, run the tests and shut down services when the tests have completed: - -```bash -docker compose -f docker-compose-e2e-tests.yml up --exit-code-from e2e-tests -``` - -The Docker Compose configuration includes a container, `build-frontend` to build the front end in production mode, necessary as in development mode Webpack builds the static assets URLs to `od.odl.local`, not available on the Docker network. The project root on your local filesystem is mounted to both this and the `watch` container from the main [docker-compose.yml](../docker-compose.yml) file, so will overwrite - during development you will need the watch container to fire again to produce a development build. To run use: - -```bash -docker compose -f docker-compose-e2e-tests.yml up build-frontend -``` - -This runs the local equivalent: - -```bash -NODE_ENV=production yarn build -``` - -## Data Handling - -Applying and tearing down data adds significant overhead to writing tests. This can be minimized by specifying initial fixture data alongside any tests that run against it. The data can be applied to a fresh ephemeral database locally and in CI and can be disposed of after a test run. This also guarantees that tests are dependent only on the codebase and not any data that happens to have been set during an instances lifetime on a hosted environment. We have the added benefit that we do not need to write teardown code to leave the database in its original state. - -These test fixtures can be written in JSON and any files in the adjacent [./fixtures](./fixtures) directory will be applied to the database whilst standing up services in CI. The data is in [Django fixture](https://docs.djangoproject.com/en/5.0/howto/initial-data/) format for use with the manage.py [loaddata utility](https://docs.djangoproject.com/en/5.0/ref/django-admin/#loaddata). - -The [docker-compose-e2e-tests.yml](../docker-compose-e2e-tests.yml) file includes run commands on the web service to apply the fixtures. As the database is destroyed and created fresh each run, the tests use their own Postgres instance, `e2e_postgres`, to not impact local development. Whilst working on the tests locally, the fixtures can be copied to a running web container and applied with the [./scripts/apply-fixtures.sh](./scripts/apply-fixtures.sh) script. - -The tests can also insert data via the API, with the benefit that we adding test coverage for the endpoints. There will be cases where we insert data while testing the UI, such as an admin creating of learning paths or user lists. There is a general preference to test against data that has been applied during the test sequence. The fixtures are particularly useful where data is voluminous and creating via the UI would be slow, also for inserting data for the read only endpoints where data is ingested from other platforms by the ETL jobs. - -## Tag Annotations - -Playwright provides a mechanism to run only tests [annotated with a specific tag](https://playwright.dev/docs/test-annotations#tag-tests). Any tests intended to be run against live environments for post deployment check should be tagged `@sanity`. As a rule, these tests cannot make assertions against any specific data in the database, not should they do anything that would change the data. We may revisit this if we find there are key user journeys that need to be checked that do change data and perhaps can add additional tags for RC/pre-production stages or use in tandem with some data retention or cleanup strategy. - -To run tests with a specific tag, run e.g.: - -```bash -yarn test --grep @sanity -``` - -## CI - -A GitHub Actions job runs the full test suite against locally running services. - -Test reports deploy to the GitHub Pages site at https://mitodl.github.io/mit-learn/playwright-report/. diff --git a/e2e_testing/fixtures/002_carousel.json b/e2e_testing/fixtures/002_carousel.json deleted file mode 100644 index f66c58e38e..0000000000 --- a/e2e_testing/fixtures/002_carousel.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "model": "learning_resources.LearningResourceOfferor", - "fields": { - "created_on": "2024-01-01T00:00:00Z", - "updated_on": "2024-01-01T00:00:00Z", - "code": "mitx", - "name": "MITx", - "professional": false - } - }, - { - "model": "learning_resources.LearningResource", - "fields": { - "id": 100000, - "created_on": "2024-01-01T00:00:00Z", - "updated_on": "2024-01-01T00:00:00Z", - "readable_id": "test-100000", - "title": "Test 100000", - "description": "Description", - "published": true, - "resource_type": "program", - "etl_source": "micromasters", - "professional": false, - "offered_by_id": "mitx" - } - } -] diff --git a/e2e_testing/package.json b/e2e_testing/package.json deleted file mode 100644 index 39b945cd61..0000000000 --- a/e2e_testing/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "e2e_testing", - "scripts": { - "start": "playwright test --ui", - "test": "playwright test", - "test:rc": "BASE_URL=https://rc.learn.mit.edu/ playwright test --grep @sanity", - "test:production": "BASE_URL=https://learn.mit.edu/ playwright test --grep @sanity" - }, - "devDependencies": { - "@playwright/test": "^1.42.1", - "@types/node": "^20.12.2", - "dotenv": "^16.3.1" - } -} diff --git a/e2e_testing/playwright.config.ts b/e2e_testing/playwright.config.ts deleted file mode 100644 index cfa50d2def..0000000000 --- a/e2e_testing/playwright.config.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { defineConfig, devices } from "@playwright/test" -import "dotenv/config" - -/** - * See https://playwright.dev/docs/test-configuration. - */ -export default defineConfig({ - testDir: "./tests", - - fullyParallel: true, - - forbidOnly: !!process.env.CI, - - retries: process.env.CI ? 2 : 0, - - workers: process.env.CI ? 1 : undefined, - - reporter: "html", - - use: { - baseURL: process.env.BASE_URL, - - trace: "on-first-retry", - }, - - projects: [ - { - name: "chromium", - use: { ...devices["Desktop Chrome"] }, - }, - - /* - { - name: "firefox", - use: { ...devices["Desktop Firefox"] }, - }, - - { - name: "webkit", - use: { ...devices["Desktop Safari"] }, - }, - - // Test against mobile viewports. - { - name: 'Mobile Chrome', - use: { ...devices['Pixel 5'] }, - }, - { - name: 'Mobile Safari', - use: { ...devices['iPhone 12'] }, - }, - - // Test against branded browsers. - { - name: 'Microsoft Edge', - use: { ...devices['Desktop Edge'], channel: 'msedge' }, - }, - { - name: 'Google Chrome', - use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - }, - */ - ], -}) diff --git a/e2e_testing/scripts/apply-fixtures.sh b/e2e_testing/scripts/apply-fixtures.sh deleted file mode 100755 index 17a53c9da2..0000000000 --- a/e2e_testing/scripts/apply-fixtures.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -docker compose -f docker-compose-e2e-tests.yml cp e2e_testing/fixtures web:/src/e2e_testing -docker compose -f docker-compose-e2e-tests.yml exec web python3 manage.py loaddata e2e_testing/fixtures/*.json diff --git a/e2e_testing/tests/001_home.spec.ts b/e2e_testing/tests/001_home.spec.ts deleted file mode 100644 index d38c17d301..0000000000 --- a/e2e_testing/tests/001_home.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { test, expect } from "@playwright/test" - -test.describe("Home page", () => { - test("Loads and main elements are visible @sanity", async ({ page }) => { - await page.goto("/") - - await expect( - page.getByRole("link", { name: "MIT Learn" }), - "Header link is visible", - ).toBeVisible() - }) -}) diff --git a/e2e_testing/tests/002_carousel.spec.ts b/e2e_testing/tests/002_carousel.spec.ts deleted file mode 100644 index 32a56dbc5d..0000000000 --- a/e2e_testing/tests/002_carousel.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { test, expect } from "@playwright/test" - -test.describe("Home page upcoming courses carousel", () => { - test("Page section renders correctly @sanity", async ({ page }) => { - await page.goto("/") - - await expect( - page.getByRole("heading", { name: "Upcoming Courses" }), - "Upcoming courses header is visible", - ).toBeVisible() - }) - - test("Carousel item renders correctly", async ({ page }) => { - await page.goto("/") - - await expect( - page - .locator("section") - .filter({ - hasText: "Upcoming Courses", - }) - .getByRole("tab"), - ).toHaveText(["All", "Professional"]) - }) -}) diff --git a/e2e_testing/tsconfig.json b/e2e_testing/tsconfig.json deleted file mode 100644 index df90b03c33..0000000000 --- a/e2e_testing/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "./", - "skipLibCheck": true - } -} diff --git a/e2e_testing/yarn.lock b/e2e_testing/yarn.lock deleted file mode 100644 index f2c656571c..0000000000 --- a/e2e_testing/yarn.lock +++ /dev/null @@ -1,928 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 8 - cacheKey: 10 - -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" - dependencies: - string-width: "npm:^5.1.2" - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: "npm:^7.0.1" - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: "npm:^8.1.0" - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 10/e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 - languageName: node - linkType: hard - -"@npmcli/agent@npm:^2.0.0": - version: 2.2.2 - resolution: "@npmcli/agent@npm:2.2.2" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^10.0.1" - socks-proxy-agent: "npm:^8.0.3" - checksum: 10/96fc0036b101bae5032dc2a4cd832efb815ce9b33f9ee2f29909ee49d96a0026b3565f73c507a69eb8603f5cb32e0ae45a70cab1e2655990a4e06ae99f7f572a - languageName: node - linkType: hard - -"@npmcli/fs@npm:^3.1.0": - version: 3.1.1 - resolution: "@npmcli/fs@npm:3.1.1" - dependencies: - semver: "npm:^7.3.5" - checksum: 10/1e0e04087049b24b38bc0b30d87a9388ee3ca1d3fdfc347c2f77d84fcfe6a51f250bc57ba2c1f614d7e4285c6c62bf8c769bc19aa0949ea39e5b043ee023b0bd - languageName: node - linkType: hard - -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 10/115e8ceeec6bc69dff2048b35c0ab4f8bbee12d8bb6c1f4af758604586d802b6e669dcb02dda61d078de42c2b4ddce41b3d9e726d7daa6b4b850f4adbf7333ff - languageName: node - linkType: hard - -"@playwright/test@npm:^1.42.1": - version: 1.46.0 - resolution: "@playwright/test@npm:1.46.0" - dependencies: - playwright: "npm:1.46.0" - bin: - playwright: cli.js - checksum: 10/710bf451555e67476bf6e911a07ec0e011474f769a10f8073b3b22fe9b81086a83b6821da354900a6d6d14d60e4320b2c9f7249cc5480e3923de56a8501b7ffe - languageName: node - linkType: hard - -"@types/node@npm:^20.12.2": - version: 20.14.14 - resolution: "@types/node@npm:20.14.14" - dependencies: - undici-types: "npm:~5.26.4" - checksum: 10/035bc347e3de04888d537801e23eb4b4f99522975ca002dbfef978edd853710031b7cd43bf022670d6aba4ed5d4ac75ea1b5ff77ff8f80998bffd943b7bcef48 - languageName: node - linkType: hard - -"abbrev@npm:^2.0.0": - version: 2.0.0 - resolution: "abbrev@npm:2.0.0" - checksum: 10/ca0a54e35bea4ece0ecb68a47b312e1a9a6f772408d5bcb9051230aaa94b0460671c5b5c9cb3240eb5b7bc94c52476550eb221f65a0bbd0145bdc9f3113a6707 - languageName: node - linkType: hard - -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": - version: 7.1.1 - resolution: "agent-base@npm:7.1.1" - dependencies: - debug: "npm:^4.3.4" - checksum: 10/c478fec8f79953f118704d007a38f2a185458853f5c45579b9669372bd0e12602e88dc2ad0233077831504f7cd6fcc8251c383375bba5eaaf563b102938bda26 - languageName: node - linkType: hard - -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: - clean-stack: "npm:^2.0.0" - indent-string: "npm:^4.0.0" - checksum: 10/1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 10/2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b - languageName: node - linkType: hard - -"ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 10/1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 - languageName: node - linkType: hard - -"ansi-styles@npm:^4.0.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: "npm:^2.0.1" - checksum: 10/b4494dfbfc7e4591b4711a396bd27e540f8153914123dccb4cdbbcb514015ada63a3809f362b9d8d4f6b17a706f1d7bea3c6f974b15fa5ae76b5b502070889ff - languageName: node - linkType: hard - -"ansi-styles@npm:^6.1.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: 10/70fdf883b704d17a5dfc9cde206e698c16bcd74e7f196ab821511651aee4f9f76c9514bdfa6ca3a27b5e49138b89cb222a28caf3afe4567570139577f991df32 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10/9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" - dependencies: - balanced-match: "npm:^1.0.0" - checksum: 10/a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 - languageName: node - linkType: hard - -"cacache@npm:^18.0.0": - version: 18.0.4 - resolution: "cacache@npm:18.0.4" - dependencies: - "@npmcli/fs": "npm:^3.1.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^10.2.2" - lru-cache: "npm:^10.0.1" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^4.0.0" - ssri: "npm:^10.0.0" - tar: "npm:^6.1.11" - unique-filename: "npm:^3.0.0" - checksum: 10/ca2f7b2d3003f84d362da9580b5561058ccaecd46cba661cbcff0375c90734b610520d46b472a339fd032d91597ad6ed12dde8af81571197f3c9772b5d35b104 - languageName: node - linkType: hard - -"chownr@npm:^2.0.0": - version: 2.0.0 - resolution: "chownr@npm:2.0.0" - checksum: 10/c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f - languageName: node - linkType: hard - -"clean-stack@npm:^2.0.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 10/2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: "npm:~1.1.4" - checksum: 10/fa00c91b4332b294de06b443923246bccebe9fab1b253f7fe1772d37b06a2269b4039a85e309abe1fe11b267b11c08d1d0473fda3badd6167f57313af2887a64 - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: 10/b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.0": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10/e1a13869d2f57d974de0d9ef7acbf69dc6937db20b918525a01dacb5032129bd552d290d886d981e99f1b624cb03657084cc87bd40f115c07ecf376821c729ce - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.3.4": - version: 4.3.6 - resolution: "debug@npm:4.3.6" - dependencies: - ms: "npm:2.1.2" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10/d3adb9af7d57a9e809a68f404490cf776122acca16e6359a2702c0f462e510e91f9765c07f707b8ab0d91e03bad57328f3256f5082631cefb5393d0394d50fb7 - languageName: node - linkType: hard - -"dotenv@npm:^16.3.1": - version: 16.4.5 - resolution: "dotenv@npm:16.4.5" - checksum: 10/55a3134601115194ae0f924e54473459ed0d9fc340ae610b676e248cca45aa7c680d86365318ea964e6da4e2ea80c4514c1adab5adb43d6867fb57ff068f95c8 - languageName: node - linkType: hard - -"e2e_testing@workspace:.": - version: 0.0.0-use.local - resolution: "e2e_testing@workspace:." - dependencies: - "@playwright/test": "npm:^1.42.1" - "@types/node": "npm:^20.12.2" - dotenv: "npm:^16.3.1" - languageName: unknown - linkType: soft - -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 10/9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: 10/c72d67a6821be15ec11997877c437491c313d924306b8da5d87d2a2bcc2cec9903cb5b04ee1a088460501d8e5b44f10df82fdc93c444101a7610b80c8b6938e1 - languageName: node - linkType: hard - -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 10/915acf859cea7131dac1b2b5c9c8e35c4849e325a1d114c30adb8cd615970f6dca0e27f64f3a4949d7d6ed86ecd79a1c5c63f02e697513cddd7b5835c90948b8 - languageName: node - linkType: hard - -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: "npm:^0.6.2" - checksum: 10/bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 10/65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e - languageName: node - linkType: hard - -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 10/1d20d825cdcce8d811bfbe86340f4755c02655a7feb2f13f8c880566d9d72a3f6c92c192a6867632e490d6da67b678271f46e01044996a6443e870331100dfdd - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.1 - resolution: "exponential-backoff@npm:3.1.1" - checksum: 10/2d9bbb6473de7051f96790d5f9a678f32e60ed0aa70741dc7fdc96fec8d631124ec3374ac144387604f05afff9500f31a1d45bd9eee4cdc2e4f9ad2d9b9d5dbd - languageName: node - linkType: hard - -"foreground-child@npm:^3.1.0": - version: 3.3.0 - resolution: "foreground-child@npm:3.3.0" - dependencies: - cross-spawn: "npm:^7.0.0" - signal-exit: "npm:^4.0.1" - checksum: 10/e3a60480f3a09b12273ce2c5fcb9514d98dd0e528f58656a1b04680225f918d60a2f81f6a368f2f3b937fcee9cfc0cbf16f1ad9a0bc6a3a6e103a84c9a90087e - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0": - version: 2.1.0 - resolution: "fs-minipass@npm:2.1.0" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/03191781e94bc9a54bd376d3146f90fe8e082627c502185dbf7b9b3032f66b0b142c1115f3b2cc5936575fc1b44845ce903dd4c21bec2a8d69f3bd56f9cee9ec - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/af143246cf6884fe26fa281621d45cfe111d34b30535a475bfa38dafe343dadb466c047a924ffc7d6b7b18265df4110224ce3803806dbb07173bf2087b648d7f - languageName: node - linkType: hard - -"fsevents@npm:2.3.2": - version: 2.3.2 - resolution: "fsevents@npm:2.3.2" - dependencies: - node-gyp: "npm:latest" - checksum: 10/6b5b6f5692372446ff81cf9501c76e3e0459a4852b3b5f1fc72c103198c125a6b8c72f5f166bdd76ffb2fca261e7f6ee5565daf80dca6e571e55bcc589cc1256 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin": - version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" - dependencies: - node-gyp: "npm:latest" - conditions: os=darwin - languageName: node - linkType: hard - -"glob@npm:^10.2.2, glob@npm:^10.3.10": - version: 10.4.5 - resolution: "glob@npm:10.4.5" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^3.1.2" - minimatch: "npm:^9.0.4" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^1.11.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10/698dfe11828b7efd0514cd11e573eaed26b2dff611f0400907281ce3eab0c1e56143ef9b35adc7c77ecc71fba74717b510c7c223d34ca8a98ec81777b293d4ac - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 10/362d5ed66b12ceb9c0a328fb31200b590ab1b02f4a254a697dc796850cc4385603e75f53ec59f768b2dad3bfa1464bd229f7de278d2899a0e3beffc634b6683f - languageName: node - linkType: hard - -"http-proxy-agent@npm:^7.0.0": - version: 7.0.2 - resolution: "http-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10/d062acfa0cb82beeb558f1043c6ba770ea892b5fb7b28654dbc70ea2aeea55226dd34c02a294f6c1ca179a5aa483c4ea641846821b182edbd9cc5d89b54c6848 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": - version: 7.0.5 - resolution: "https-proxy-agent@npm:7.0.5" - dependencies: - agent-base: "npm:^7.0.2" - debug: "npm:4" - checksum: 10/6679d46159ab3f9a5509ee80c3a3fc83fba3a920a5e18d32176c3327852c3c00ad640c0c4210a8fd70ea3c4a6d3a1b375bf01942516e7df80e2646bdc77658ab - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10/2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 10/cd3f5cbc9ca2d624c6a1f53f12e6b341659aba0e2d3254ae2b4464aaea8b4294cdb09616abbc59458f980531f2429784ed6a420d48d245bcad0811980c9efae9 - languageName: node - linkType: hard - -"ip-address@npm:^9.0.5": - version: 9.0.5 - resolution: "ip-address@npm:9.0.5" - dependencies: - jsbn: "npm:1.1.0" - sprintf-js: "npm:^1.1.3" - checksum: 10/1ed81e06721af012306329b31f532b5e24e00cb537be18ddc905a84f19fe8f83a09a1699862bf3a1ec4b9dea93c55a3fa5faf8b5ea380431469df540f38b092c - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 10/44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - -"is-lambda@npm:^1.0.1": - version: 1.0.1 - resolution: "is-lambda@npm:1.0.1" - checksum: 10/93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10/7c9f715c03aff08f35e98b1fadae1b9267b38f0615d501824f9743f3aab99ef10e303ce7db3f186763a0b70a19de5791ebfc854ff884d5a8c4d92211f642ec92 - languageName: node - linkType: hard - -"isexe@npm:^3.1.1": - version: 3.1.1 - resolution: "isexe@npm:3.1.1" - checksum: 10/7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e - languageName: node - linkType: hard - -"jackspeak@npm:^3.1.2": - version: 3.4.3 - resolution: "jackspeak@npm:3.4.3" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10/96f8786eaab98e4bf5b2a5d6d9588ea46c4d06bbc4f2eb861fdd7b6b182b16f71d8a70e79820f335d52653b16d4843b29dd9cdcf38ae80406756db9199497cf3 - languageName: node - linkType: hard - -"jsbn@npm:1.1.0": - version: 1.1.0 - resolution: "jsbn@npm:1.1.0" - checksum: 10/bebe7ae829bbd586ce8cbe83501dd8cb8c282c8902a8aeeed0a073a89dc37e8103b1244f3c6acd60278bcbfe12d93a3f83c9ac396868a3b3bbc3c5e5e3b648ef - languageName: node - linkType: hard - -"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": - version: 10.4.3 - resolution: "lru-cache@npm:10.4.3" - checksum: 10/e6e90267360476720fa8e83cc168aa2bf0311f3f2eea20a6ba78b90a885ae72071d9db132f40fda4129c803e7dcec3a6b6a6fbb44ca90b081630b810b5d6a41a - languageName: node - linkType: hard - -"make-fetch-happen@npm:^13.0.0": - version: 13.0.1 - resolution: "make-fetch-happen@npm:13.0.1" - dependencies: - "@npmcli/agent": "npm:^2.0.0" - cacache: "npm:^18.0.0" - http-cache-semantics: "npm:^4.1.1" - is-lambda: "npm:^1.0.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^3.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^0.6.3" - proc-log: "npm:^4.2.0" - promise-retry: "npm:^2.0.1" - ssri: "npm:^10.0.0" - checksum: 10/11bae5ad6ac59b654dbd854f30782f9de052186c429dfce308eda42374528185a100ee40ac9ffdc36a2b6c821ecaba43913e4730a12f06f15e895ea9cb23fa59 - languageName: node - linkType: hard - -"minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348 - languageName: node - linkType: hard - -"minipass-collect@npm:^2.0.1": - version: 2.0.1 - resolution: "minipass-collect@npm:2.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 - languageName: node - linkType: hard - -"minipass-fetch@npm:^3.0.0": - version: 3.0.5 - resolution: "minipass-fetch@npm:3.0.5" - dependencies: - encoding: "npm:^0.1.13" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^1.0.3" - minizlib: "npm:^2.1.2" - dependenciesMeta: - encoding: - optional: true - checksum: 10/c669948bec1373313aaa8f104b962a3ced9f45c49b26366a4b0ae27ccdfa9c5740d72c8a84d3f8623d7a61c5fc7afdfda44789008c078f61a62441142efc4a97 - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/40982d8d836a52b0f37049a0a7e5d0f089637298e6d9b45df9c115d4f0520682a78258905e5c8b180fb41b593b0a82cc1361d2c74b45f7ada66334f84d1ecfdd - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10/a5c6ef069f70d9a524d3428af39f2b117ff8cd84172e19b754e7264a33df460873e6eb3d6e55758531580970de50ae950c496256bb4ad3691a2974cddff189f0 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass@npm:5.0.0" - checksum: 10/61682162d29f45d3152b78b08bab7fb32ca10899bc5991ffe98afc18c9e9543bd1e3be94f8b8373ba6262497db63607079dc242ea62e43e7b2270837b7347c93 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": - version: 7.1.2 - resolution: "minipass@npm:7.1.2" - checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 - languageName: node - linkType: hard - -"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": - version: 2.1.2 - resolution: "minizlib@npm:2.1.2" - dependencies: - minipass: "npm:^3.0.0" - yallist: "npm:^4.0.0" - checksum: 10/ae0f45436fb51344dcb87938446a32fbebb540d0e191d63b35e1c773d47512e17307bf54aa88326cc6d176594d00e4423563a091f7266c2f9a6872cdc1e234d1 - languageName: node - linkType: hard - -"mkdirp@npm:^1.0.3": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: 10/d71b8dcd4b5af2fe13ecf3bd24070263489404fe216488c5ba7e38ece1f54daf219e72a833a3a2dc404331e870e9f44963a33399589490956bff003a3404d3b2 - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 10/673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f - languageName: node - linkType: hard - -"negotiator@npm:^0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: 10/2723fb822a17ad55c93a588a4bc44d53b22855bf4be5499916ca0cab1e7165409d0b288ba2577d7b029f10ce18cf2ed8e703e5af31c984e1e2304277ef979837 - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 10.2.0 - resolution: "node-gyp@npm:10.2.0" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - glob: "npm:^10.3.10" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^13.0.0" - nopt: "npm:^7.0.0" - proc-log: "npm:^4.1.0" - semver: "npm:^7.3.5" - tar: "npm:^6.2.1" - which: "npm:^4.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10/41773093b1275751dec942b985982fd4e7a69b88cae719b868babcef3880ee6168aaec8dcaa8cd0b9fa7c84873e36cc549c6cac6a124ee65ba4ce1f1cc108cfe - languageName: node - linkType: hard - -"nopt@npm:^7.0.0": - version: 7.2.1 - resolution: "nopt@npm:7.2.1" - dependencies: - abbrev: "npm:^2.0.0" - bin: - nopt: bin/nopt.js - checksum: 10/95a1f6dec8a81cd18cdc2fed93e6f0b4e02cf6bdb4501c848752c6e34f9883d9942f036a5e3b21a699047d8a448562d891e67492df68ec9c373e6198133337ae - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: "npm:^3.0.0" - checksum: 10/7ba4a2b1e24c05e1fc14bbaea0fc6d85cf005ae7e9c9425d4575550f37e2e584b1af97bcde78eacd7559208f20995988d52881334db16cf77bc1bcf68e48ed7c - languageName: node - linkType: hard - -"package-json-from-dist@npm:^1.0.0": - version: 1.0.0 - resolution: "package-json-from-dist@npm:1.0.0" - checksum: 10/ac706ec856a5a03f5261e4e48fa974f24feb044d51f84f8332e2af0af04fbdbdd5bbbfb9cbbe354190409bc8307c83a9e38c6672c3c8855f709afb0006a009ea - languageName: node - linkType: hard - -"path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 10/55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 - languageName: node - linkType: hard - -"path-scurry@npm:^1.11.1": - version: 1.11.1 - resolution: "path-scurry@npm:1.11.1" - dependencies: - lru-cache: "npm:^10.2.0" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10/5e8845c159261adda6f09814d7725683257fcc85a18f329880ab4d7cc1d12830967eae5d5894e453f341710d5484b8fdbbd4d75181b4d6e1eb2f4dc7aeadc434 - languageName: node - linkType: hard - -"playwright-core@npm:1.46.0": - version: 1.46.0 - resolution: "playwright-core@npm:1.46.0" - bin: - playwright-core: cli.js - checksum: 10/1fd237d01380be0d650ae7df73fb796eae9c208e0746bb110db270139f1d2a96bf3b8856c394a48720b30e145614a10f275ab08627d0c95ba2160dc0402a90cb - languageName: node - linkType: hard - -"playwright@npm:1.46.0": - version: 1.46.0 - resolution: "playwright@npm:1.46.0" - dependencies: - fsevents: "npm:2.3.2" - playwright-core: "npm:1.46.0" - dependenciesMeta: - fsevents: - optional: true - bin: - playwright: cli.js - checksum: 10/e06f3b53faaf4edf4fcf636b43004dd0db1e45dbdcb2b59037a9810dfce3a59f0386d4826ba7de42f98fe525539fa20dd8f8c46acd1f8e5c57dcb5c1d8d536ce - languageName: node - linkType: hard - -"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": - version: 4.2.0 - resolution: "proc-log@npm:4.2.0" - checksum: 10/4e1394491b717f6c1ade15c570ecd4c2b681698474d3ae2d303c1e4b6ab9455bd5a81566211e82890d5a5ae9859718cc6954d5150bb18b09b72ecb297beae90a - languageName: node - linkType: hard - -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: "npm:^2.0.2" - retry: "npm:^0.12.0" - checksum: 10/96e1a82453c6c96eef53a37a1d6134c9f2482f94068f98a59145d0986ca4e497bf110a410adf73857e588165eab3899f0ebcf7b3890c1b3ce802abc0d65967d4 - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: 10/7eaf7a0cf37cc27b42fb3ef6a9b1df6e93a1c6d98c6c6702b02fe262d5fcbd89db63320793b99b21cb5348097d0a53de81bd5f4e8b86e20cc9412e3f1cfb4e83 - languageName: node - linkType: hard - -"semver@npm:^7.3.5": - version: 7.6.3 - resolution: "semver@npm:7.6.3" - bin: - semver: bin/semver.js - checksum: 10/36b1fbe1a2b6f873559cd57b238f1094a053dbfd997ceeb8757d79d1d2089c56d1321b9f1069ce263dc64cfa922fa1d2ad566b39426fe1ac6c723c1487589e10 - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10/6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10/1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 - languageName: node - linkType: hard - -"signal-exit@npm:^4.0.1": - version: 4.1.0 - resolution: "signal-exit@npm:4.1.0" - checksum: 10/c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: 10/927484aa0b1640fd9473cee3e0a0bcad6fce93fd7bbc18bac9ad0c33686f5d2e2c422fba24b5899c184524af01e11dd2bd051c2bf2b07e47aff8ca72cbfc60d2 - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^8.0.3": - version: 8.0.4 - resolution: "socks-proxy-agent@npm:8.0.4" - dependencies: - agent-base: "npm:^7.1.1" - debug: "npm:^4.3.4" - socks: "npm:^2.8.3" - checksum: 10/c8e7c2b398338b49a0a0f4d2bae5c0602aeeca6b478b99415927b6c5db349ca258448f2c87c6958ebf83eea17d42cbc5d1af0bfecb276cac10b9658b0f07f7d7 - languageName: node - linkType: hard - -"socks@npm:^2.8.3": - version: 2.8.3 - resolution: "socks@npm:2.8.3" - dependencies: - ip-address: "npm:^9.0.5" - smart-buffer: "npm:^4.2.0" - checksum: 10/ffcb622c22481dfcd7589aae71fbfd71ca34334064d181df64bf8b7feaeee19706aba4cffd1de35cc7bbaeeaa0af96be2d7f40fcbc7bc0ab69533a7ae9ffc4fb - languageName: node - linkType: hard - -"sprintf-js@npm:^1.1.3": - version: 1.1.3 - resolution: "sprintf-js@npm:1.1.3" - checksum: 10/e7587128c423f7e43cc625fe2f87e6affdf5ca51c1cc468e910d8aaca46bb44a7fbcfa552f787b1d3987f7043aeb4527d1b99559e6621e01b42b3f45e5a24cbb - languageName: node - linkType: hard - -"ssri@npm:^10.0.0": - version: 10.0.6 - resolution: "ssri@npm:10.0.6" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/f92c1b3cc9bfd0a925417412d07d999935917bc87049f43ebec41074661d64cf720315661844106a77da9f8204b6d55ae29f9514e673083cae39464343af2a8b - languageName: node - linkType: hard - -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: "npm:^8.0.0" - is-fullwidth-code-point: "npm:^3.0.0" - strip-ansi: "npm:^6.0.1" - checksum: 10/e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb - languageName: node - linkType: hard - -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: "npm:^0.2.0" - emoji-regex: "npm:^9.2.2" - strip-ansi: "npm:^7.0.1" - checksum: 10/7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 - languageName: node - linkType: hard - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": - version: 6.0.1 - resolution: "strip-ansi@npm:6.0.1" - dependencies: - ansi-regex: "npm:^5.0.1" - checksum: 10/ae3b5436d34fadeb6096367626ce987057713c566e1e7768818797e00ac5d62023d0f198c4e681eae9e20701721980b26a64a8f5b91238869592a9c6800719a2 - languageName: node - linkType: hard - -"strip-ansi@npm:^7.0.1": - version: 7.1.0 - resolution: "strip-ansi@npm:7.1.0" - dependencies: - ansi-regex: "npm:^6.0.1" - checksum: 10/475f53e9c44375d6e72807284024ac5d668ee1d06010740dec0b9744f2ddf47de8d7151f80e5f6190fc8f384e802fdf9504b76a7e9020c9faee7103623338be2 - languageName: node - linkType: hard - -"tar@npm:^6.1.11, tar@npm:^6.2.1": - version: 6.2.1 - resolution: "tar@npm:6.2.1" - dependencies: - chownr: "npm:^2.0.0" - fs-minipass: "npm:^2.0.0" - minipass: "npm:^5.0.0" - minizlib: "npm:^2.1.1" - mkdirp: "npm:^1.0.3" - yallist: "npm:^4.0.0" - checksum: 10/bfbfbb2861888077fc1130b84029cdc2721efb93d1d1fb80f22a7ac3a98ec6f8972f29e564103bbebf5e97be67ebc356d37fa48dbc4960600a1eb7230fbd1ea0 - languageName: node - linkType: hard - -"undici-types@npm:~5.26.4": - version: 5.26.5 - resolution: "undici-types@npm:5.26.5" - checksum: 10/0097779d94bc0fd26f0418b3a05472410408877279141ded2bd449167be1aed7ea5b76f756562cb3586a07f251b90799bab22d9019ceba49c037c76445f7cddd - languageName: node - linkType: hard - -"unique-filename@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-filename@npm:3.0.0" - dependencies: - unique-slug: "npm:^4.0.0" - checksum: 10/8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df - languageName: node - linkType: hard - -"unique-slug@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-slug@npm:4.0.0" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10/40912a8963fc02fb8b600cf50197df4a275c602c60de4cac4f75879d3c48558cfac48de08a25cc10df8112161f7180b3bbb4d662aadb711568602f9eddee54f0 - languageName: node - linkType: hard - -"which@npm:^2.0.1": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: "npm:^2.0.0" - bin: - node-which: ./bin/node-which - checksum: 10/4782f8a1d6b8fc12c65e968fea49f59752bf6302dc43036c3bf87da718a80710f61a062516e9764c70008b487929a73546125570acea95c5b5dcc8ac3052c70f - languageName: node - linkType: hard - -"which@npm:^4.0.0": - version: 4.0.0 - resolution: "which@npm:4.0.0" - dependencies: - isexe: "npm:^3.1.1" - bin: - node-which: bin/which.js - checksum: 10/f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651 - languageName: node - linkType: hard - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: "npm:^4.0.0" - string-width: "npm:^4.1.0" - strip-ansi: "npm:^6.0.0" - checksum: 10/cebdaeca3a6880da410f75209e68cd05428580de5ad24535f22696d7d9cab134d1f8498599f344c3cf0fb37c1715807a183778d8c648d6cc0cb5ff2bb4236540 - languageName: node - linkType: hard - -"wrap-ansi@npm:^8.1.0": - version: 8.1.0 - resolution: "wrap-ansi@npm:8.1.0" - dependencies: - ansi-styles: "npm:^6.1.0" - string-width: "npm:^5.0.1" - strip-ansi: "npm:^7.0.1" - checksum: 10/7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 10/4cb02b42b8a93b5cf50caf5d8e9beb409400a8a4d85e83bb0685c1457e9ac0b7a00819e9f5991ac25ffabb56a78e2f017c1acc010b3a1babfe6de690ba531abd - languageName: node - linkType: hard diff --git a/env/ci.env b/env/ci.env deleted file mode 100644 index f3f22bc430..0000000000 --- a/env/ci.env +++ /dev/null @@ -1,18 +0,0 @@ -# This file is committed to Git. Ensure there are no secrets in it. -NODE_ENV=production -DEV_ENV=True -DATABASE_URL=postgres://postgres:postgres@db:5432/e2e_postgres # pragma: allowlist secret -MITOL_SECURE_SSL_REDIRECT=False -MITOL_DB_DISABLE_SSL=True -MITOL_FEATURES_DEFAULT=True -OPENSEARCH_URL=opensearch-node-mitopen-1:9200 -CELERY_TASK_ALWAYS_EAGER=False -CELERY_BROKER_URL=redis://redis:6379/4 -CELERY_RESULT_BACKEND=redis://redis:6379/4 -TIKA_CLIENT_ONLY=True -MITOL_APP_BASE_URL=http://localhost:8063/ -MAILGUN_KEY=fake_mailgun_key -MAILGUN_SENDER_DOMAIN=other.fake.site -OPENSEARCH_INDEX=testindex -MITOL_COOKIE_DOMAIN=localhost -MITOL_COOKIE_NAME=cookie_monster diff --git a/frontends/.eslintrc.js b/frontends/.eslintrc.js index 636672dcc9..c8899203db 100644 --- a/frontends/.eslintrc.js +++ b/frontends/.eslintrc.js @@ -72,7 +72,6 @@ module.exports = { "**/*.stories.ts", "**/*.stories.tsx", "**/*.mdx", - "e2e_testing/**/*.ts", ], }, ], diff --git a/frontends/README.md b/frontends/README.md index f0dbe2c5b7..a2f9ca30c8 100644 --- a/frontends/README.md +++ b/frontends/README.md @@ -8,8 +8,8 @@ Each subdirectory of `/frontends` is a yarn workspace: ``` frontends/ -├─ mit-learn/ ... built by webpack and served by django -├─ package1/ ... a dependency of app/ +├─ main/ ... Next.js frontend +├─ package1/ ... a dependency of main/ ├─ package2/ ├─ etc... ``` diff --git a/frontends/jest.config.ts b/frontends/jest.config.ts index eaeecce315..8d1cba518d 100644 --- a/frontends/jest.config.ts +++ b/frontends/jest.config.ts @@ -10,7 +10,6 @@ const projectsConfig: Config.InitialOptions = { collectCoverage: true, coverageDirectory: "coverage", projects: ["/*/jest.config.ts"], - modulePathIgnorePatterns: ["/mit-learn/"], watchPlugins: [ "jest-watch-typeahead/filename", "jest-watch-typeahead/testname", diff --git a/frontends/main/.gitignore b/frontends/main/.gitignore index 1dd45b2022..515fe71d07 100644 --- a/frontends/main/.gitignore +++ b/frontends/main/.gitignore @@ -37,3 +37,5 @@ next-env.d.ts # Sentry Config File .env.sentry-build-plugin + +certificates diff --git a/frontends/main/next.config.js b/frontends/main/next.config.js index b10fc8fd9d..aa0d40a825 100644 --- a/frontends/main/next.config.js +++ b/frontends/main/next.config.js @@ -24,13 +24,13 @@ const nextConfig = { productionBrowserSourceMaps: true, async rewrites() { return [ - /* Images moved from /static, though image paths are sometimes + /* Static assets moved from /static, though image paths are sometimes * returned on the API, e.g. /api/v0/channels/type/unit/ocw/ - * TODO update API paths and remove the rewrite. + * Also rewrites requests for /static/hash.txt */ { - source: "/static/images/:path*", - destination: "/images/:path*", + source: "/static/:path*", + destination: "/:path*", }, ] }, diff --git a/frontends/mit-learn/public/images/blank.png b/frontends/main/public/images/blank.png similarity index 100% rename from frontends/mit-learn/public/images/blank.png rename to frontends/main/public/images/blank.png diff --git a/frontends/main/tsconfig.json b/frontends/main/tsconfig.json index e36e578d3b..87bc071c48 100644 --- a/frontends/main/tsconfig.json +++ b/frontends/main/tsconfig.json @@ -37,5 +37,5 @@ ".next/types/**/*.ts", "../jest.jsdom.config" ], - "exclude": ["node_modules", "../mit-learn/**/*.tsx"] + "exclude": ["node_modules"] } diff --git a/frontends/mit-learn/package.json b/frontends/mit-learn/package.json deleted file mode 100644 index be90326f1b..0000000000 --- a/frontends/mit-learn/package.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "name": "mit-learn", - "version": "0.0.0", - "private": true, - "license": "BSD-3-Clause", - "repository": { - "type": "git", - "url": "https://github.com/mitodl/mit-learn.git" - }, - "scripts": { - "watch": "NODE_ENV=development LOAD_ENV_FILES=true webpack serve", - "watch:docker": "NODE_ENV=development webpack serve", - "build": "webpack --config webpack.config.js --bail", - "build-exports": "webpack --config webpack.exports.js --bail" - }, - "devDependencies": { - "@emotion/react": "^11.11.1", - "@emotion/styled": "^11.11.0", - "@faker-js/faker": "^8.0.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", - "@storybook/addon-essentials": "^8.0.9", - "@storybook/addon-interactions": "^8.0.9", - "@storybook/addon-links": "^8.0.9", - "@storybook/blocks": "^8.0.9", - "@storybook/react": "^8.0.9", - "@storybook/react-webpack5": "^8.0.9", - "@storybook/test": "^8.0.9", - "@swc/core": "^1.4.11", - "@swc/plugin-emotion": "^4.0.0", - "@testing-library/react": "14.3.1", - "@testing-library/user-event": "14.5.2", - "@types/lodash": "^4.14.182", - "@types/react-refresh": "^0", - "@types/react-slick": "^0", - "@types/slick-carousel": "^1", - "copy-webpack-plugin": "^12.0.2", - "css-loader": "^6.10.0", - "dotenv": "^16.4.5", - "envalid": "^8.0.0", - "html-webpack-plugin": "^5.6.0", - "mini-css-extract-plugin": "^2.6.1", - "ol-test-utilities": "0.0.0", - "react-refresh": "^0.14.2", - "storybook": "^8.1.10", - "swc-loader": "^0.2.6", - "tsconfig-paths-webpack-plugin": "^4.1.0", - "webpack": "^5.91.0", - "webpack-bundle-analyzer": "^4.10.1", - "webpack-bundle-tracker": "^1.4.0", - "webpack-cli": "^5.1.4", - "webpack-dev-middleware": "^7.2.1", - "webpack-dev-server": "^5.0.4", - "webpack-hot-middleware": "^2.26.1", - "webpack-merge": "^5.10.0", - "yaml": "^2.4.2" - }, - "dependencies": { - "@ebay/nice-modal-react": "^1.2.13", - "@mitodl/course-search-utils": "^3.2.5", - "@remixicon/react": "^4.2.0", - "@sentry/react": "^7.57.0", - "@tanstack/react-query": "^4.36.1", - "@tanstack/react-query-devtools": "^4.29.6", - "api": "workspace:*", - "axios": "^1.6.3", - "classnames": "^2.3.2", - "enforce-unique": "^1.3.0", - "formik": "^2.4.5", - "lodash": "^4.17.21", - "ol-ckeditor": "0.0.0", - "ol-components": "0.0.0", - "ol-utilities": "0.0.0", - "ol-widgets": "0.0.0", - "posthog-js": "^1.128.2", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-helmet-async": "^2.0.3", - "react-infinite-scroller": "^1.2.6", - "react-router": "^6.22.2", - "react-router-dom": "^6.22.2", - "react-slick": "^0.30.2", - "slick-carousel": "^1.8.1", - "tiny-invariant": "^1.3.1", - "yup": "^1.2.0" - }, - "engines": { - "node": "^20", - "yarn": "^3.8.1" - } -} diff --git a/frontends/mit-learn/public/favicon.ico b/frontends/mit-learn/public/favicon.ico deleted file mode 100644 index 95d530203d..0000000000 Binary files a/frontends/mit-learn/public/favicon.ico and /dev/null differ diff --git a/frontends/mit-learn/public/favicon.svg b/frontends/mit-learn/public/favicon.svg deleted file mode 100644 index a10ede3133..0000000000 --- a/frontends/mit-learn/public/favicon.svg +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/frontends/mit-learn/public/images/MIT_circle.svg b/frontends/mit-learn/public/images/MIT_circle.svg deleted file mode 100644 index 2d1bc1b26b..0000000000 --- a/frontends/mit-learn/public/images/MIT_circle.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - Group 8 - Created with Sketch. - - - - - - - - - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/MIT_circle_red.jpg b/frontends/mit-learn/public/images/MIT_circle_red.jpg deleted file mode 100644 index 9d4a2ca8a1..0000000000 Binary files a/frontends/mit-learn/public/images/MIT_circle_red.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/MIT_circle_red.svg b/frontends/mit-learn/public/images/MIT_circle_red.svg deleted file mode 100644 index c42060115a..0000000000 --- a/frontends/mit-learn/public/images/MIT_circle_red.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - Group 8 - Created with Sketch. - - - - - - - - - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/apple_podcasts.png b/frontends/mit-learn/public/images/apple_podcasts.png deleted file mode 100644 index 6562e6e541..0000000000 Binary files a/frontends/mit-learn/public/images/apple_podcasts.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/avatar_default.png b/frontends/mit-learn/public/images/avatar_default.png deleted file mode 100644 index ed15c10516..0000000000 Binary files a/frontends/mit-learn/public/images/avatar_default.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/certificate_icon.png b/frontends/mit-learn/public/images/certificate_icon.png deleted file mode 100644 index 0edf1780e7..0000000000 Binary files a/frontends/mit-learn/public/images/certificate_icon.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/certificate_icon_infinite.png b/frontends/mit-learn/public/images/certificate_icon_infinite.png deleted file mode 100644 index 646c26b198..0000000000 Binary files a/frontends/mit-learn/public/images/certificate_icon_infinite.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/channel_avatar_default.svg b/frontends/mit-learn/public/images/channel_avatar_default.svg deleted file mode 100644 index 59f40e35d7..0000000000 --- a/frontends/mit-learn/public/images/channel_avatar_default.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-0.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-0.svg deleted file mode 100644 index ad7fa45305..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-0.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-1.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-1.svg deleted file mode 100644 index 30a4e15f7d..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-1.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-2.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-2.svg deleted file mode 100644 index 68bddacaa8..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-2.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-3.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-3.svg deleted file mode 100644 index 6ad1a7b0ea..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-3.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-4.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-4.svg deleted file mode 100644 index cf22a1c233..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-4.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-5.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-5.svg deleted file mode 100644 index 1b68a52aad..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-5.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-6.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-6.svg deleted file mode 100644 index 9c30a5cb86..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-6.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-7.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-7.svg deleted file mode 100644 index 14a5622af0..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-7.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-8.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-8.svg deleted file mode 100644 index eb83f16a17..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-8.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-9.svg b/frontends/mit-learn/public/images/channel_avatars/channel-avatar-9.svg deleted file mode 100644 index 75dcc091bf..0000000000 --- a/frontends/mit-learn/public/images/channel_avatars/channel-avatar-9.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/channel_banner_default.svg b/frontends/mit-learn/public/images/channel_banner_default.svg deleted file mode 100644 index d74b78aa84..0000000000 --- a/frontends/mit-learn/public/images/channel_banner_default.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/frontends/mit-learn/public/images/ctl-logo.svg b/frontends/mit-learn/public/images/ctl-logo.svg deleted file mode 100644 index 645efd7f88..0000000000 --- a/frontends/mit-learn/public/images/ctl-logo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontends/mit-learn/public/images/default_resource_thumb.jpg b/frontends/mit-learn/public/images/default_resource_thumb.jpg deleted file mode 100644 index 385db118e6..0000000000 Binary files a/frontends/mit-learn/public/images/default_resource_thumb.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/edx_logo.png b/frontends/mit-learn/public/images/edx_logo.png deleted file mode 100644 index 99eb011f2f..0000000000 Binary files a/frontends/mit-learn/public/images/edx_logo.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/favicon.ico b/frontends/mit-learn/public/images/favicon.ico deleted file mode 100644 index 95d530203d..0000000000 Binary files a/frontends/mit-learn/public/images/favicon.ico and /dev/null differ diff --git a/frontends/mit-learn/public/images/google_podcasts.png b/frontends/mit-learn/public/images/google_podcasts.png deleted file mode 100644 index 30924a0db6..0000000000 Binary files a/frontends/mit-learn/public/images/google_podcasts.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/hero-background-texture.jpeg b/frontends/mit-learn/public/images/hero-background-texture.jpeg deleted file mode 100644 index b525ea342e..0000000000 Binary files a/frontends/mit-learn/public/images/hero-background-texture.jpeg and /dev/null differ diff --git a/frontends/mit-learn/public/images/infinite-front-page-image.png b/frontends/mit-learn/public/images/infinite-front-page-image.png deleted file mode 100644 index e33e86bb86..0000000000 Binary files a/frontends/mit-learn/public/images/infinite-front-page-image.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/learn-og-image.jpg b/frontends/mit-learn/public/images/learn-og-image.jpg deleted file mode 100644 index cf57a0decd..0000000000 Binary files a/frontends/mit-learn/public/images/learn-og-image.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-and-logo.jpg b/frontends/mit-learn/public/images/mit-and-logo.jpg deleted file mode 100644 index 584fa27390..0000000000 Binary files a/frontends/mit-learn/public/images/mit-and-logo.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-block-logo.jpg b/frontends/mit-learn/public/images/mit-block-logo.jpg deleted file mode 100644 index 5e61d900e8..0000000000 Binary files a/frontends/mit-learn/public/images/mit-block-logo.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-bootcamp-logo.png b/frontends/mit-learn/public/images/mit-bootcamp-logo.png deleted file mode 100644 index 2d808c3777..0000000000 Binary files a/frontends/mit-learn/public/images/mit-bootcamp-logo.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-dome-2.jpg b/frontends/mit-learn/public/images/mit-dome-2.jpg deleted file mode 100644 index ee78d2f4e5..0000000000 Binary files a/frontends/mit-learn/public/images/mit-dome-2.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-dome.jpg b/frontends/mit-learn/public/images/mit-dome.jpg deleted file mode 100644 index c979f6376d..0000000000 Binary files a/frontends/mit-learn/public/images/mit-dome.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-learn-logo.jpg b/frontends/mit-learn/public/images/mit-learn-logo.jpg deleted file mode 100644 index 488eae1e1b..0000000000 Binary files a/frontends/mit-learn/public/images/mit-learn-logo.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-learn-logo.svg b/frontends/mit-learn/public/images/mit-learn-logo.svg deleted file mode 100644 index 0069f62884..0000000000 --- a/frontends/mit-learn/public/images/mit-learn-logo.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/frontends/mit-learn/public/images/mit-logo-black.svg b/frontends/mit-learn/public/images/mit-logo-black.svg deleted file mode 100644 index 7f1fef3d1e..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-black.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-color.svg b/frontends/mit-learn/public/images/mit-logo-color.svg deleted file mode 100644 index 67da18b013..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-color.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - -logo2 - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-darkgrey.svg b/frontends/mit-learn/public/images/mit-logo-darkgrey.svg deleted file mode 100644 index 111009ca73..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-darkgrey.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - -MIT large lightgray and white logo - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-learn-white.svg b/frontends/mit-learn/public/images/mit-logo-learn-white.svg deleted file mode 100644 index c46990cc9a..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-learn-white.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-learn.svg b/frontends/mit-learn/public/images/mit-logo-learn.svg deleted file mode 100644 index 14878e5100..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-learn.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-micromasters.jpg b/frontends/mit-learn/public/images/mit-logo-micromasters.jpg deleted file mode 100644 index 5e77cd2f6c..0000000000 Binary files a/frontends/mit-learn/public/images/mit-logo-micromasters.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-logo-white.svg b/frontends/mit-learn/public/images/mit-logo-white.svg deleted file mode 100644 index 5b0774426b..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-white.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo.jpg b/frontends/mit-learn/public/images/mit-logo.jpg deleted file mode 100644 index b36c8d1df2..0000000000 Binary files a/frontends/mit-learn/public/images/mit-logo.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-micromasters-logo.png b/frontends/mit-learn/public/images/mit-micromasters-logo.png deleted file mode 100644 index 36b494b742..0000000000 Binary files a/frontends/mit-learn/public/images/mit-micromasters-logo.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-ocw-logo-square.png b/frontends/mit-learn/public/images/mit-ocw-logo-square.png deleted file mode 100644 index 217133f9d9..0000000000 Binary files a/frontends/mit-learn/public/images/mit-ocw-logo-square.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/mitpe-logo.png b/frontends/mit-learn/public/images/mitpe-logo.png deleted file mode 100644 index 7f1a28e1e3..0000000000 Binary files a/frontends/mit-learn/public/images/mitpe-logo.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/mitx-logo.png b/frontends/mit-learn/public/images/mitx-logo.png deleted file mode 100644 index 63ae394106..0000000000 Binary files a/frontends/mit-learn/public/images/mitx-logo.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/navdrawer/upcoming.svg b/frontends/mit-learn/public/images/navdrawer/upcoming.svg deleted file mode 100644 index 55a3304c9f..0000000000 --- a/frontends/mit-learn/public/images/navdrawer/upcoming.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/frontends/mit-learn/public/images/open-bg-texture-wgradient.jpg b/frontends/mit-learn/public/images/open-bg-texture-wgradient.jpg deleted file mode 100644 index ac1c5f2e0a..0000000000 Binary files a/frontends/mit-learn/public/images/open-bg-texture-wgradient.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/open-bg-texture-with-gradient.svg b/frontends/mit-learn/public/images/open-bg-texture-with-gradient.svg deleted file mode 100644 index f17f0d9076..0000000000 --- a/frontends/mit-learn/public/images/open-bg-texture-with-gradient.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/open_content_icon.png b/frontends/mit-learn/public/images/open_content_icon.png deleted file mode 100644 index 8bc5c48a2b..0000000000 Binary files a/frontends/mit-learn/public/images/open_content_icon.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/podcast_cover_art.png b/frontends/mit-learn/public/images/podcast_cover_art.png deleted file mode 100644 index b195991af7..0000000000 Binary files a/frontends/mit-learn/public/images/podcast_cover_art.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/podcasts_bg.png b/frontends/mit-learn/public/images/podcasts_bg.png deleted file mode 100644 index 9de8dd8138..0000000000 Binary files a/frontends/mit-learn/public/images/podcasts_bg.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/podcasts_bg_mobile.png b/frontends/mit-learn/public/images/podcasts_bg_mobile.png deleted file mode 100644 index 946a698443..0000000000 Binary files a/frontends/mit-learn/public/images/podcasts_bg_mobile.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/professional_education_background.png b/frontends/mit-learn/public/images/professional_education_background.png deleted file mode 100644 index 86065d2511..0000000000 Binary files a/frontends/mit-learn/public/images/professional_education_background.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/professional_icon.png b/frontends/mit-learn/public/images/professional_icon.png deleted file mode 100644 index 594f39795f..0000000000 Binary files a/frontends/mit-learn/public/images/professional_icon.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/rss_logo.png b/frontends/mit-learn/public/images/rss_logo.png deleted file mode 100644 index d95eb527fb..0000000000 Binary files a/frontends/mit-learn/public/images/rss_logo.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/scc-logo.svg b/frontends/mit-learn/public/images/scc-logo.svg deleted file mode 100644 index eec11ba1fc..0000000000 --- a/frontends/mit-learn/public/images/scc-logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontends/mit-learn/public/images/sloan-logo.png b/frontends/mit-learn/public/images/sloan-logo.png deleted file mode 100644 index ee4f67b49d..0000000000 Binary files a/frontends/mit-learn/public/images/sloan-logo.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/social/LICENSE.txt b/frontends/mit-learn/public/images/social/LICENSE.txt deleted file mode 100644 index c2f512f465..0000000000 --- a/frontends/mit-learn/public/images/social/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-2017 Cole Bemis - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/frontends/mit-learn/public/images/social/feather-sprite.svg b/frontends/mit-learn/public/images/social/feather-sprite.svg deleted file mode 100644 index 183faf1268..0000000000 --- a/frontends/mit-learn/public/images/social/feather-sprite.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontends/mit-learn/public/images/stata_curved.png b/frontends/mit-learn/public/images/stata_curved.png deleted file mode 100644 index 84e8c6a590..0000000000 Binary files a/frontends/mit-learn/public/images/stata_curved.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/video_play_overlay.png b/frontends/mit-learn/public/images/video_play_overlay.png deleted file mode 100644 index 79ee30930f..0000000000 Binary files a/frontends/mit-learn/public/images/video_play_overlay.png and /dev/null differ diff --git a/frontends/mit-learn/public/index.html b/frontends/mit-learn/public/index.html deleted file mode 100644 index db71cb559f..0000000000 --- a/frontends/mit-learn/public/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - <% if (MITOL_NOINDEX) { %> - - <% } %> - - - - - <% if (APPZI_URL) { %> - - <% } %> - - - -
- - diff --git a/frontends/mit-learn/public/robots.txt b/frontends/mit-learn/public/robots.txt deleted file mode 100644 index eb0536286f..0000000000 --- a/frontends/mit-learn/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: diff --git a/frontends/mit-learn/src/App.tsx b/frontends/mit-learn/src/App.tsx deleted file mode 100644 index ce61e432b9..0000000000 --- a/frontends/mit-learn/src/App.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from "react" -import { createRoot } from "react-dom/client" -import { createBrowserRouter } from "react-router-dom" -import invariant from "tiny-invariant" -import * as Sentry from "@sentry/react" -import { createQueryClient } from "@/services/react-query/react-query" -import routes from "./routes" -import AppProviders from "./AppProviders" - -Sentry.init({ - dsn: APP_SETTINGS.SENTRY_DSN, - release: APP_SETTINGS.VERSION, - environment: APP_SETTINGS.SENTRY_ENV, - integrations: [ - Sentry.browserTracingIntegration(), - Sentry.browserProfilingIntegration(), - ], - profilesSampleRate: APP_SETTINGS.SENTRY_PROFILES_SAMPLE_RATE, - tracesSampleRate: APP_SETTINGS.SENTRY_TRACES_SAMPLE_RATE, - tracePropagationTargets: [APP_SETTINGS.MITOL_API_BASE_URL], -}) - -const container = document.getElementById("app-container") -invariant(container, "Could not find container element") -const root = createRoot(container) - -const router = createBrowserRouter(routes) -const queryClient = createQueryClient() - -root.render() diff --git a/frontends/mit-learn/src/AppProviders.test.tsx b/frontends/mit-learn/src/AppProviders.test.tsx deleted file mode 100644 index 2fdd906635..0000000000 --- a/frontends/mit-learn/src/AppProviders.test.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from "react" - -import { renderWithProviders, screen } from "./test-utils" - -jest.mock("posthog-js/react", () => ({ - PostHogProvider: (props: { children: React.ReactNode }) => ( -
{props.children}
- ), -})) - -describe("PostHogProvider", () => { - it("Renders with PostHog support if enabled", async () => { - APP_SETTINGS.POSTHOG = { - api_key: "12345", // pragma: allowlist secret - } - - renderWithProviders(
) - - const phProvider = screen.getAllByTestId("phProvider") - - expect(phProvider.length).toBe(1) - }) - - it("Renders without PostHog support if disabled", async () => { - APP_SETTINGS.POSTHOG = { - api_key: "", // pragma: allowlist secret - } - - renderWithProviders(
) - - const phProvider = screen.queryAllByTestId("phProvider") - - expect(phProvider.length).toBe(0) - }) -}) diff --git a/frontends/mit-learn/src/AppProviders.tsx b/frontends/mit-learn/src/AppProviders.tsx deleted file mode 100644 index 99fac0f5a3..0000000000 --- a/frontends/mit-learn/src/AppProviders.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React, { StrictMode } from "react" -import { HelmetProvider } from "react-helmet-async" -import { RouterProvider } from "react-router-dom" -import type { RouterProviderProps } from "react-router-dom" -import { QueryClientProvider, QueryClient } from "@tanstack/react-query" -import { ReactQueryDevtools } from "@tanstack/react-query-devtools" -import { Provider as NiceModalProvider } from "@ebay/nice-modal-react" -import { ThemeProvider } from "ol-components" -import GlobalStyles from "./GlobalStyles" -import { PostHogProvider } from "posthog-js/react" -import type { PostHogSettings } from "./types/settings" - -interface AppProps { - router: RouterProviderProps["router"] - queryClient: QueryClient -} - -/** - * Renders child with Router, QueryClientProvider, and other such context provides. - */ -const AppProviders: React.FC = ({ router, queryClient }) => { - const { POSTHOG } = APP_SETTINGS - - const phSettings: PostHogSettings = POSTHOG?.api_key?.length - ? POSTHOG - : { - api_key: "", - } - - const phOptions = { - feature_flag_request_timeout_ms: phSettings.timeout || 3000, - bootstrap: { - featureFlags: phSettings.bootstrap_flags, - }, - } - - const interiorElements = ( - - - - - - - - - - - - ) - - return phSettings.api_key.length > 0 ? ( - - - {interiorElements} - - - ) : ( - {interiorElements} - ) -} - -export default AppProviders diff --git a/frontends/mit-learn/src/ExportedComponentProviders.tsx b/frontends/mit-learn/src/ExportedComponentProviders.tsx deleted file mode 100644 index c7760e2a1d..0000000000 --- a/frontends/mit-learn/src/ExportedComponentProviders.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { StrictMode } from "react" -import { QueryClientProvider, QueryClient } from "@tanstack/react-query" -import { ReactQueryDevtools } from "@tanstack/react-query-devtools" -import { Provider as NiceModalProvider } from "@ebay/nice-modal-react" -import { ThemeProvider } from "ol-components" - -interface ExportedComponentProps { - queryClient: QueryClient -} - -/** - * Renders child with Router, QueryClientProvider, and other such context provides. - */ -const ExportedComponentProviders: React.FC = ({ - queryClient, -}) => { - const interiorElements = ( - - - - - - - ) - - return {interiorElements} -} - -export default ExportedComponentProviders diff --git a/frontends/mit-learn/src/ExportedComponents.tsx b/frontends/mit-learn/src/ExportedComponents.tsx deleted file mode 100644 index 4c498da558..0000000000 --- a/frontends/mit-learn/src/ExportedComponents.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react" -import { createRoot } from "react-dom/client" -import { AddToUserListDialogInner } from "@/page-components/Dialogs/AddToListDialog" -import NiceModal from "@ebay/nice-modal-react" -import { createQueryClient } from "@/services/react-query/react-query" -import ExportedComponentProviders from "@/ExportedComponentProviders" -import { useLearningResourcesList } from "api/hooks/learningResources" - -const initMitOpenDom = (container: HTMLElement) => { - const root = createRoot(container) - const queryClient = createQueryClient() - return root.render() -} - -type ExportedDialogProps = { - readableId: string -} - -const AddToUserListDialogComponent: React.FC = ({ - readableId, -}) => { - const resourcesQuery = useLearningResourcesList({ readable_id: [readableId] }) - const response = resourcesQuery.data ?? null - if (response === null) return null - const resourceId = response.results[0].id - return ( - - ) -} - -const openAddToUserListDialog = (readableId: string) => { - const addToUserListDialog = NiceModal.create(AddToUserListDialogComponent) - NiceModal.show(addToUserListDialog, { readableId }) -} - -export { initMitOpenDom, openAddToUserListDialog } diff --git a/frontends/mit-learn/src/page-components/ArticleUpsertForm/ArticleUpsertForm.tsx b/frontends/mit-learn/src/page-components/ArticleUpsertForm/ArticleUpsertForm.tsx deleted file mode 100644 index fc4e7ad9ff..0000000000 --- a/frontends/mit-learn/src/page-components/ArticleUpsertForm/ArticleUpsertForm.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import React, { useCallback } from "react" -import { useToggle } from "ol-utilities" -import { CkeditorArticleLazy } from "ol-ckeditor" -import { - useArticleDetail, - useArticlePartialUpdate, - useArticleDestroy, - useArticleCreate, -} from "api/hooks/articles" -import { - Button, - FormHelperText, - Grid, - TextField, - Dialog, - styled, -} from "ol-components" -import * as Yup from "yup" -import { useFormik } from "formik" -import { Article } from "api" -import invariant from "tiny-invariant" - -const configOverrides = { placeholder: "Write your article here..." } - -const postSchema = Yup.object().shape({ - title: Yup.string().default("").required("Title is required"), - html: Yup.string().default("").required("Article body is required"), -}) - -type FormValues = Yup.InferType - -const FormFooter = styled(Grid)` - margin-top: 1rem; - margin-bottom: 1rem; -` - -const FormControls = styled(Grid)` - display: flex; - justify-content: flex-end; - align-items: center; - - > *:not(:last-child) { - margin-right: 0.5rem; - } - - > *:not(:first-of-type) { - margin-left: 0.5rem; - } -` - -type ArticleFormProps = { - id?: Article["id"] - onSaved?: (id: number) => void - onCancel?: () => void - onDestroy?: () => void -} - -const ArticleUpsertForm = ({ - id, - onDestroy, - onCancel, - onSaved, -}: ArticleFormProps) => { - const [editoryReady, setEditorReady] = useToggle(false) - const [editorBusy, setEditorBusy] = useToggle(false) - const editArticle = useArticlePartialUpdate() - const createArticle = useArticleCreate() - const article = useArticleDetail(id) - - const hasData = (!id || article.data) && editoryReady - - const [confirmationOpen, toggleConfirmationOpen] = useToggle(false) - const destroyArticle = useArticleDestroy() - const handleSubmit = useCallback( - async (e: FormValues) => { - let data: Article - if (id) { - data = await editArticle.mutateAsync({ ...e, id }) - } else { - data = await createArticle.mutateAsync({ ...e }) - } - onSaved?.(data.id) - }, - [id, editArticle, createArticle, onSaved], - ) - const handleDestroy = useCallback(async () => { - invariant(id) - await destroyArticle.mutateAsync(id) - toggleConfirmationOpen.off() - onDestroy?.() - }, [id, destroyArticle, toggleConfirmationOpen, onDestroy]) - const formik = useFormik({ - enableReinitialize: true, - initialValues: article.data ?? { title: "", html: "" }, - onSubmit: handleSubmit, - validationSchema: postSchema, - validateOnChange: false, - validateOnBlur: false, - }) - - return ( -
- - { - formik.setFieldValue("html", value) - }} - config={configOverrides} - /> - {formik.errors.html ? ( - {formik.errors.html} - ) : null} - - - - {id ? ( - - ) : null} - - - - - - - - Are you sure you want to delete {article.data?.title}? - - - ) -} - -export default ArticleUpsertForm diff --git a/frontends/mit-learn/src/page-components/MetaTags/MetaTags.test.tsx b/frontends/mit-learn/src/page-components/MetaTags/MetaTags.test.tsx deleted file mode 100644 index b314884bfc..0000000000 --- a/frontends/mit-learn/src/page-components/MetaTags/MetaTags.test.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import React from "react" -import { assertPartialMetas, renderWithProviders, waitFor } from "@/test-utils" -import MetaTags from "./MetaTags" -import { faker } from "@faker-js/faker/locale/en" - -const NODE_ENV = process.env.NODE_ENV - -describe("MetaTags", () => { - afterEach(() => { - // Some tests here manipulate NODE_ENV, so let's reset it - process.env.NODE_ENV = NODE_ENV - }) - test("Sets expected tags", async () => { - const title = faker.lorem.words() - const description = faker.lorem.paragraph() - const image = faker.image.url() - const imageAlt = faker.lorem.paragraph() - renderWithProviders( - , - ) - - const expectedTitle = `${title} | ${APP_SETTINGS.SITE_NAME}` - await waitFor(() => { - assertPartialMetas({ - title: expectedTitle, - description, - og: { title: expectedTitle, description, image, imageAlt }, - twitter: { image, description, card: "summary_large_image" }, - }) - }) - }) - - test("Does not render social tags when social=false", async () => { - const title = faker.lorem.words() - const description = faker.lorem.paragraph() - const image = faker.image.url() - const imageAlt = faker.lorem.paragraph() - renderWithProviders( - , - ) - - const expectedTitle = `${title} | ${APP_SETTINGS.SITE_NAME}` - await waitFor(() => { - assertPartialMetas({ - title: expectedTitle, - description, - og: { - title: undefined, - description: undefined, - image: undefined, - imageAlt: undefined, - }, - twitter: { image: undefined, description: undefined, card: undefined }, - }) - }) - }) - - test("Does not set title if absent", async () => { - const description = faker.lorem.words() - renderWithProviders() - await waitFor(() => assertPartialMetas({ description })) - expect(document.querySelector("title")).toBe(null) - expect(document.querySelector('meta[property="og:title"]')).toBe(null) - }) - - test("Does not set description if absent", async () => { - const title = faker.lorem.words() - renderWithProviders() - await waitFor(() => - assertPartialMetas({ title: `${title} | ${APP_SETTINGS.SITE_NAME}` }), - ) - expect(document.querySelector('meta[name="description"]')).toBe(null) - expect(document.querySelector('meta[name="og:description"]')).toBe(null) - expect(document.querySelector('meta[name="twitter:description"]')).toBe( - null, - ) - }) - - test.each([ - { url: "/some/path", expected: "/some/path" }, - { url: "/some/path/", expected: "/some/path" }, - { url: "/some/path?", expected: "/some/path" }, - { url: "/some/path/?", expected: "/some/path" }, - { url: "/some/path?a=1", expected: "/some/path?a=1" }, - { url: "/some/path/?a=1", expected: "/some/path?a=1" }, - ])("Canonicalizes the url", async ({ url, expected }) => { - const description = faker.lorem.words() - renderWithProviders(, { url }) - await waitFor(() => assertPartialMetas({ description })) - expect(document.querySelector('link[rel="canonical"]')).toHaveAttribute( - "href", - window.origin + expected, - ) - }) -}) diff --git a/frontends/mit-learn/src/page-components/MetaTags/MetaTags.tsx b/frontends/mit-learn/src/page-components/MetaTags/MetaTags.tsx deleted file mode 100644 index 31d4aff502..0000000000 --- a/frontends/mit-learn/src/page-components/MetaTags/MetaTags.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { RESOURCE_DRAWER_QUERY_PARAM } from "@/common/urls" -import React from "react" -import { Helmet } from "react-helmet-async" -import { useLocation } from "react-router" -import invariant from "tiny-invariant" - -type MetaTagsProps = { - title?: string - description?: string | null - image?: string - imageAlt?: string | null - canonicalLink?: string - children?: React.ReactNode - social?: boolean - /** - * Keeps rendered when resource drawer is open. - * - * tldr: Set `isResourceDrawer={true}` if this MetaTags component is used in - * the resource drawer. Otherwise, the MetaTags component will be unmounted - * when resource drawer is open. - * - * Full story: `react-helmet-async` tries to intelligently deduplicate the - * meta tags. Precedence is given to the most recently INITIALIZED instance of - * (Not the most recently rendered). - * - * If the helmets are: - * - * - * - * - * - * - * - * - * - * - * - * - * - * Then "D" will be the title, because it is the most recently initialized. - * Even if FooComponent re-renders its Helmet with a new title, then "D" will - * still be the title because initialization order matters, not render order. - * - * This generally leads to exactly the behavior you would want: Pages can each - * have their own Helmet instances, and child components within a Page can add - * their own metadata tags with higher precedence, since the children will - * initialize after the parent. - * - * HOWEVER: The resource drawer is not a child of any particular page. It's - * a modal drawer that is available on ALL pages: - * - * - * - * - * - * - * - * Because the resource drawer is not a child of any particular page, its - * Helmet instance might initialze before or after PageOne's Helmet (depending - * on whether the page waits for a data fetch or not.) - * - * In order to guarantee that the resource drawer's Helmet instance is - * initialized last, we unmount all other Helmet instances when the drawer is - * open. - */ - isResourceDrawer?: boolean -} - -const canonicalPathname = (pathname: string) => { - return pathname.endsWith("/") ? pathname.slice(0, -1) : pathname -} - -const SITE_NAME = APP_SETTINGS.SITE_NAME -const DEFAULT_OG_IMAGE = `${window.origin}/static/images/learn-og-image.jpg` -/** - * Renders a Helmet component to customize meta tags - */ -const MetaTags: React.FC = ({ - title, - description, - image = DEFAULT_OG_IMAGE, - imageAlt, - children, - social = true, - isResourceDrawer, -}) => { - const location = useLocation() - - const searchString = location.search === "?" ? "" : location.search - const canonical = new URL( - canonicalPathname(location.pathname) + searchString, - window.location.origin, - ).toString() - - const isResourceDrawerOpen = new URLSearchParams(location.search).has( - RESOURCE_DRAWER_QUERY_PARAM, - ) - - const fullTitle = `${title} | ${SITE_NAME}` - - if (process.env.NODE_ENV === "development" && image) { - try { - new URL(image) - } catch { - throw new Error("og:image must be a full URL, including protocol") - } - invariant(!image.endsWith(".svg"), "og:image must not be an SVG") - } - - if (isResourceDrawerOpen && !isResourceDrawer) { - return null - } - - return ( - - {title && {fullTitle}} - {description && } - - {/* - react-helmet-async does not allow fragments as children - */} - {social && } - {social && } - {social && } - {social && title && } - {social && imageAlt && ( - - )} - {social && } - {social && description && ( - - )} - {social && } - {social && } - {social && description && ( - - )} - {children} - - ) -} - -export default MetaTags diff --git a/frontends/mit-learn/src/page-components/Profile/types.ts b/frontends/mit-learn/src/page-components/Profile/types.ts deleted file mode 100644 index 16558a9c47..0000000000 --- a/frontends/mit-learn/src/page-components/Profile/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react" - -import type { Profile, PatchedProfileRequest } from "api/v0" - -export type ProfileFieldUpdateable = keyof PatchedProfileRequest & keyof Profile - -export type ProfileFieldUpdateFunc< - FieldName extends ProfileFieldUpdateable = ProfileFieldUpdateable, -> = (name: FieldName, value: PatchedProfileRequest[FieldName]) => void - -export interface ProfileFieldUpdateProps< - FieldName extends ProfileFieldUpdateable, -> { - onUpdate: ProfileFieldUpdateFunc - value?: Profile[FieldName] - label: React.ReactNode -} - -export type ProfileFieldStateHook< - T extends ProfileFieldUpdateable, - E = React.ChangeEventHandler, -> = (value: Profile[T], onUpdate: ProfileFieldUpdateFunc) => [Profile[T], E] diff --git a/frontends/mit-learn/src/pages/ArticleDetailsPage/ArticleDetailsPage.test.tsx b/frontends/mit-learn/src/pages/ArticleDetailsPage/ArticleDetailsPage.test.tsx deleted file mode 100644 index 3a6f8b5cda..0000000000 --- a/frontends/mit-learn/src/pages/ArticleDetailsPage/ArticleDetailsPage.test.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { renderTestApp, screen, waitFor } from "../../test-utils" -import type { Article } from "api" -import { articles as factory } from "api/test-utils/factories" -import { setMockResponse, urls } from "api/test-utils" - -const setup = ({ article }: { article: Article }) => { - setMockResponse.get(urls.articles.details(article.id), article) - renderTestApp({ - url: `/articles/${article.id}`, - user: { is_article_editor: true }, - }) -} - -describe("ArticleDetailsPage", () => { - it("Renders title and html", async () => { - const article = factory.article() - setup({ article }) - await screen.findByRole("heading", { - name: article.title, - }) - screen.getByText(article.html) - - await waitFor(() => { - expect(document.title).toBe(`${article.title} | MIT Learn`) - }) - }) - - it("Shows a link to the edit page", async () => { - const article = factory.article() - setup({ article }) - const link = await screen.findByRole("link", { - name: "Edit", - }) - expect(link.href.endsWith(`/articles/${article.id}/edit`)).toBe(true) - }) -}) diff --git a/frontends/mit-learn/src/pages/ArticleDetailsPage/ArticleDetailsPage.tsx b/frontends/mit-learn/src/pages/ArticleDetailsPage/ArticleDetailsPage.tsx deleted file mode 100644 index 89e82c32a1..0000000000 --- a/frontends/mit-learn/src/pages/ArticleDetailsPage/ArticleDetailsPage.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React from "react" -import { GridColumn, GridContainer } from "@/components/GridLayout/GridLayout" -import { - Container, - LoadingSpinner, - BannerPage, - ButtonLink, - Grid, -} from "ol-components" -import { useArticleDetail } from "api/hooks/articles" -import { useParams } from "react-router" -import { articlesEditView } from "@/common/urls" -import { CkeditorDisplay } from "ol-ckeditor" -import MetaTags from "@/page-components/MetaTags/MetaTags" - -type RouteParams = { - id: string -} - -const ArticlesDetailPage: React.FC = () => { - const id = Number(useParams().id) - const article = useArticleDetail(id) - - return ( - - - - - - {article.data ? ( - <> - -

{article.data?.title}

-
- - - Edit - - - - ) : ( - - - - )} - -
-
-
-
- ) -} - -export default ArticlesDetailPage diff --git a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleCreatePage.test.tsx b/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleCreatePage.test.tsx deleted file mode 100644 index 3013d3a23d..0000000000 --- a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleCreatePage.test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react" -import { screen, user, renderWithProviders } from "../../test-utils" -import { articles as factory } from "api/test-utils/factories" -import { makeRequest, setMockResponse, urls } from "api/test-utils" -import ArticleCreatePage from "./ArticleCreatePage" - -describe("ArticleCreatePage", () => { - test("Has 'Save' and 'Cancel' but not 'Delete' buttons", async () => { - renderWithProviders() - await screen.findByRole("button", { name: "Save" }) - await screen.findByRole("button", { name: "Cancel" }) - const deleteButton = screen.queryByRole("button", { name: "Delete" }) - - expect(deleteButton).toBe(null) - }) - - test("Calls creation endpoint when saved", async () => { - const article = factory.article() - const { location } = renderWithProviders() - const titleInput = await screen.findByLabelText(/Title/) - const bodyInput = screen.getByTestId("mock-ckeditor") - const saveButton = screen.getByRole("button", { name: "Save" }) - - await user.click(titleInput) - await user.paste(article.title) - await user.click(bodyInput) - await user.paste(article.html) - - setMockResponse.post(urls.articles.list(), article) - await user.click(saveButton) - expect(makeRequest).toHaveBeenCalledWith("post", urls.articles.list(), { - title: article.title, - html: article.html, - }) - - expect(location.current.pathname).toBe(`/articles/${article.id}`) - }) -}) diff --git a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleCreatePage.tsx b/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleCreatePage.tsx deleted file mode 100644 index 6ccc275594..0000000000 --- a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleCreatePage.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React, { useCallback } from "react" -import { useNavigate } from "react-router" -import ArticleUpsertForm from "@/page-components/ArticleUpsertForm/ArticleUpsertForm" -import { articlesView } from "@/common/urls" -import ArticleUpsertPage from "./ArticleUpsertPage" - -/** - * Create new articles. - */ -export const ArticleCreatePage: React.FC = () => { - const navigate = useNavigate() - const goHome = useCallback(() => navigate("/"), [navigate]) - const viewDetails = useCallback( - (id: number) => navigate(articlesView(id)), - [navigate], - ) - return ( - - - - ) -} - -export default ArticleCreatePage diff --git a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleEditPage.test.tsx b/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleEditPage.test.tsx deleted file mode 100644 index c4bcc6560c..0000000000 --- a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleEditPage.test.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import React from "react" -import { - renderRoutesWithProviders, - screen, - user, - waitFor, -} from "../../test-utils" -import type { Article } from "api" -import { articles as factory } from "api/test-utils/factories" -import { makeRequest, setMockResponse, urls } from "api/test-utils" -import { getDescriptionFor } from "ol-test-utilities" -import ArticleEditPage from "./ArticleEditPage" - -describe("ArticleEditPage", () => { - const setup = ({ article }: { article: Article }) => { - setMockResponse.get(urls.articles.details(article.id), article) - renderRoutesWithProviders( - [ - { - path: "/articles/:id/edit", - element: , - }, - { - path: "*", - element: null, - }, - ], - { url: `/articles/${article.id}/edit` }, - ) - } - - it("Renders title and html into form inputs", async () => { - const article = factory.article() - setup({ article }) - const bodyInput = await screen.findByText(article.html) - const titleInput = screen.getByLabelText(/Title/i) - - expect(titleInput).toHaveValue(article.title) - // It should actually be CKEditor, but we mock CKEditor with a textarea for jest - expect(bodyInput).toBeInstanceOf(HTMLTextAreaElement) - - await waitFor(() => { - expect(document.title).toBe(`${article.title} | Edit | MIT Learn`) - }) - }) - - it("Updates fields and makes appropriate API calls", async () => { - const article = factory.article() - setup({ article }) - const bodyInput = await screen.findByText(article.html) - const titleInput = screen.getByLabelText(/Title/i) - const patch = { title: "New title", html: "

New body

" } - const url = urls.articles.details(article.id) - setMockResponse.patch(url, patch) - - await user.click(titleInput) - await user.clear(titleInput) - await user.paste(patch.title) - - await user.click(bodyInput) - await user.clear(bodyInput) - await user.paste(patch.html) - - await user.click(screen.getByText(/Save/i)) - - expect(makeRequest).toHaveBeenCalledWith("patch", url, patch) - }) - - it("Validates form data", async () => { - const article = factory.article({ title: "", html: "" }) - setup({ article }) - const titleInput = screen.getByLabelText(/Title/i) - - const saveButton = screen.getByRole("button", { name: /Save/i }) - await waitFor(() => expect(saveButton).toBeEnabled()) - makeRequest.mockClear() - - // Click Save - await user.click(saveButton) - // No PATCH request should be made - expect(makeRequest).not.toHaveBeenCalled() - - // Error messages should be shown. - expect(getDescriptionFor(titleInput).textContent).toMatch( - /Title is required/i, - ) - // getDescriptionFor won't work since the form description isn't properly - // associated with CKEditor - screen.getByText(/Article body is required/i) - }) - - test.each([ - { - confirmed: true, - }, - { confirmed: false }, - ])( - "Delete prompts for confirmation (confirmed=$confirmed)", - async ({ confirmed }) => { - const article = factory.article() - setup({ article }) - - const deleteButton = await screen.findByRole("button", { name: "Delete" }) - await user.click(deleteButton) - - await screen.findByRole("heading", { - name: "Are you sure?", - }) - - const cancelButton = await screen.findByRole("button", { - name: "Cancel", - }) - const confirmButton = await screen.findByRole("button", { - name: "Yes, delete", - }) - makeRequest.mockClear() - const url = urls.articles.details(article.id) - setMockResponse.delete(url, null) - await user.click(confirmed ? confirmButton : cancelButton) - - expect(makeRequest).toHaveBeenCalledTimes(confirmed ? 1 : 0) - if (confirmed) { - expect(makeRequest).toHaveBeenCalledWith("delete", url, undefined) - } - }, - ) -}) diff --git a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleEditPage.tsx b/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleEditPage.tsx deleted file mode 100644 index 01a7920536..0000000000 --- a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleEditPage.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { useCallback } from "react" -import { useNavigate, useParams } from "react-router" -import { useArticleDetail } from "api/hooks/articles" -import ArticleUpsertForm from "@/page-components/ArticleUpsertForm/ArticleUpsertForm" -import { articlesView } from "@/common/urls" -import ArticleUpsertPage from "./ArticleUpsertPage" - -type RouteParams = { - id: string -} - -/** - * Edit articles, reading article id from route. - */ -const ArticleEditPage: React.FC = () => { - const id = Number(useParams().id) - const article = useArticleDetail(id) - const navigate = useNavigate() - const returnToViewing = useCallback( - () => navigate(articlesView(id)), - [navigate, id], - ) - const goHome = useCallback(() => navigate("/"), [navigate]) - const title = article.data?.title ? `${article.data?.title} | Edit` : "Edit" - return ( - - - - ) -} - -export default ArticleEditPage diff --git a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleUpsertPage.tsx b/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleUpsertPage.tsx deleted file mode 100644 index 37d4ffb4c8..0000000000 --- a/frontends/mit-learn/src/pages/ArticleUpsertPages/ArticleUpsertPage.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from "react" -import { GridColumn, GridContainer } from "@/components/GridLayout/GridLayout" -import { Container, BannerPage } from "ol-components" -import MetaTags from "@/page-components/MetaTags/MetaTags" - -type ArticleUpsertPageProps = { - children: React.ReactNode - title: string -} - -const ArticleUpsertPage: React.FC = ({ - children, - title, -}) => { - return ( - - - - - {children} - - - - ) -} - -export default ArticleUpsertPage diff --git a/frontends/mit-learn/src/pages/ArticleUpsertPages/index.ts b/frontends/mit-learn/src/pages/ArticleUpsertPages/index.ts deleted file mode 100644 index 65096aec89..0000000000 --- a/frontends/mit-learn/src/pages/ArticleUpsertPages/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import ArticleEditPage from "./ArticleEditPage" -import ArticleCreatePage from "./ArticleCreatePage" - -export { ArticleEditPage, ArticleCreatePage } diff --git a/frontends/mit-learn/src/pages/ChannelPage/EditChannelAppearanceForm.test.tsx b/frontends/mit-learn/src/pages/ChannelPage/EditChannelAppearanceForm.test.tsx deleted file mode 100644 index ecdd46294e..0000000000 --- a/frontends/mit-learn/src/pages/ChannelPage/EditChannelAppearanceForm.test.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { - renderTestApp, - screen, - fireEvent, - user, - waitFor, -} from "../../test-utils" -import { factories, urls, setMockResponse } from "api/test-utils" -import { channels as factory } from "api/test-utils/factories" -import { makeChannelViewPath, makeChannelEditPath } from "@/common/urls" -import { makeWidgetListResponse } from "ol-widgets/src/factories" -import { ChannelTypeEnum, type Channel } from "api/v0" - -const setupApis = (channelOverrides: Partial) => { - const channel = factory.channel({ is_moderator: true, ...channelOverrides }) - setMockResponse.get(urls.userMe.get(), {}) - channel.search_filter = undefined - setMockResponse.get( - urls.learningResources.featured({ limit: 12 }), - factories.learningResources.resources({ count: 0 }), - ) - - setMockResponse.get( - urls.channels.details(channel.channel_type, channel.name), - channel, - ) - setMockResponse.get( - urls.widgetLists.details(channel.widget_list || -1), - makeWidgetListResponse({}, { count: 0 }), - ) - - setMockResponse.get(expect.stringContaining(urls.testimonials.list({})), { - results: [], - }) - - if (channel.channel_type === ChannelTypeEnum.Topic) { - const topicId = channel.topic_detail.topic - if (topicId) { - setMockResponse.get(urls.topics.get(topicId), null) - setMockResponse.get( - urls.topics.list({ parent_topic_id: [topicId] }), - null, - ) - } - } - - return channel -} - -describe("EditChannelAppearanceForm", () => { - it("Displays the channel title, appearance inputs with current channel values", async () => { - const channel = setupApis({}) - expect(channel.is_moderator).toBeTruthy() - renderTestApp({ - url: `${makeChannelEditPath(channel.channel_type, channel.name)}/#appearance`, - }) - const descInput = (await screen.findByLabelText( - "Description", - )) as HTMLInputElement - const titleInput = (await screen.findByLabelText( - "Title", - )) as HTMLInputElement - expect(titleInput.value).toEqual(channel.title) - expect(descInput.value).toEqual(channel.public_description) - }) - - it("Shows an error if a required channel is blank", async () => { - const channel = setupApis({}) - renderTestApp({ - url: `${makeChannelEditPath(channel.channel_type, channel.name)}/#appearance`, - }) - const titleInput = await screen.findByLabelText("Title") - const titleError = screen.queryByText("Title is required") - expect(titleError).toBeNull() - fireEvent.change(titleInput, { - target: { value: "" }, - }) - fireEvent.blur(titleInput) - await screen.findByText("Title is required") - }) - - it("updates channel values on form submission", async () => { - const channel = setupApis({ - featured_list: null, // so we don't have to mock userList responses - lists: [], - }) - - const newTitle = "New Title" - const newDesc = "New Description" - // Initial channel values - const updatedValues = { - ...channel, - title: newTitle, - public_description: newDesc, - } - setMockResponse.patch(urls.channels.patch(channel.id), updatedValues) - const { location } = renderTestApp({ - url: `${makeChannelEditPath(channel.channel_type, channel.name)}/#appearance`, - }) - const titleInput = (await screen.findByLabelText( - "Title", - )) as HTMLInputElement - const descInput = (await screen.findByLabelText( - "Description", - )) as HTMLInputElement - const submitBtn = await screen.findByText("Save") - titleInput.setSelectionRange(0, titleInput.value.length) - await user.type(titleInput, newTitle) - descInput.setSelectionRange(0, descInput.value.length) - await user.type(descInput, newDesc) - // Expected channel values after submit - setMockResponse.get( - urls.channels.details(channel.channel_type, channel.name), - updatedValues, - ) - if ( - channel.channel_type === ChannelTypeEnum.Topic && - channel.topic_detail.topic - ) { - setMockResponse.get( - urls.topics.get(channel.topic_detail.topic), - factories.learningResources.topic(), - ) - } - await user.click(submitBtn) - - await waitFor(() => { - expect(location.current.pathname).toBe( - makeChannelViewPath(channel.channel_type, channel.name), - ) - }) - await screen.findAllByText(newTitle) - await screen.findAllByText(newDesc) - }, 10000) -}) diff --git a/frontends/mit-learn/src/pages/ChannelPage/EditChannelAppearanceForm.tsx b/frontends/mit-learn/src/pages/ChannelPage/EditChannelAppearanceForm.tsx deleted file mode 100644 index baa0716ee2..0000000000 --- a/frontends/mit-learn/src/pages/ChannelPage/EditChannelAppearanceForm.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import React, { useCallback } from "react" -import { useRouter } from "next/navigation" -import { useFormik } from "formik" -import { RadioChoiceField, Button, TextField } from "ol-components" -import * as Yup from "yup" - -import { ChannelTypeEnum, Channel } from "api/v0" -import { makeChannelViewPath } from "@/common/urls" -import { useChannelPartialUpdate } from "api/hooks/channels" - -type FormProps = { - channel: Channel -} -const CHANNEL_TYPE_CHOICES = [ - { - value: "department", - label: "Department", - }, - { - value: "topic", - label: "Topic", - }, - { - value: "unit", - label: "Unit", - }, - { - value: "pathway", - label: "Pathway", - }, -] -const postSchema = Yup.object().shape({ - title: Yup.string().default("").required("Title is required"), - public_description: Yup.string() - .default("") - .required("Description is required"), - channel_type: Yup.string() - .oneOf(Object.values(ChannelTypeEnum)) - .default("pathway") - .required("Channel Type is required"), -}) -type FormData = Yup.InferType - -const EditChannelAppearanceForm = (props: FormProps): JSX.Element => { - const { channel } = props - const channelId = channel.id - const editChannel = useChannelPartialUpdate() - const router = useRouter() - - const handleSubmit = useCallback( - async (e: FormData) => { - const data = await editChannel.mutateAsync({ id: channelId, ...e }) - if (data) { - router.push(makeChannelViewPath(data.channel_type, data.name)) - } - return data - }, - [router, channelId, editChannel], - ) - - const formik = useFormik({ - enableReinitialize: true, - initialValues: { - title: channel.title, - public_description: String(channel.public_description), - channel_type: channel.channel_type, - }, - validationSchema: postSchema, - onSubmit: handleSubmit, - }) - - return ( -
- - - formik.setFieldValue(e.target.name, e.target.value)} - /> -
- - -
- - ) -} - -export default EditChannelAppearanceForm diff --git a/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.test.tsx b/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.test.tsx deleted file mode 100644 index 9dd9fadde3..0000000000 --- a/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.test.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { renderTestApp, screen } from "../../test-utils" -import { channels as factory } from "api/test-utils/factories" -import { setMockResponse, urls as apiUrls, factories } from "api/test-utils" -import { makeChannelEditPath } from "@/common/urls" -import { ChannelTypeEnum } from "api/v0" - -describe("EditChannelPage", () => { - const setup = () => { - const channel = factory.channel({ - is_moderator: true, - channel_type: ChannelTypeEnum.Topic, - }) - setMockResponse.get( - apiUrls.channels.details(channel.channel_type, channel.name), - channel, - ) - setMockResponse.get( - apiUrls.learningResources.featured({ limit: 12 }), - factories.learningResources.resources({ count: 0 }), - ) - setMockResponse.get( - apiUrls.userSubscription.check({ - source_type: "channel_subscription_type", - }), - factories.percolateQueries, - ) - if (channel.channel_type === ChannelTypeEnum.Topic) { - const topicId = channel.topic_detail.topic - if (topicId) { - setMockResponse.get(apiUrls.topics.get(topicId), null) - setMockResponse.get( - apiUrls.topics.list({ parent_topic_id: [topicId] }), - null, - ) - } - } - return channel - } - - it("Displays 2 tabs for moderators", async () => { - const channel = setup() - setMockResponse.get(apiUrls.userMe.get(), {}) - renderTestApp({ - url: `${makeChannelEditPath(channel.channel_type, channel.name)}/`, - }) - const tabs = screen.queryAllByRole("tab") - expect(tabs.length).toEqual(0) - }) - - it("Displays message and no tabs for non-moderators", async () => { - const channel = setup() - channel.is_moderator = false - setMockResponse.get(apiUrls.userMe.get(), {}) - setMockResponse.get( - apiUrls.learningResources.featured({ limit: 12 }), - factories.learningResources.resources({ count: 0 }), - ) - setMockResponse.get( - apiUrls.userSubscription.check({ - source_type: "channel_subscription_type", - }), - factories.percolateQueries, - ) - setMockResponse.get( - apiUrls.channels.details(channel.channel_type, channel.name), - channel, - ) - setMockResponse.get( - apiUrls.testimonials.list({ offerors: [channel.name] }), - channel, - ) - setMockResponse.get(apiUrls.testimonials.details(channel.id), channel) - renderTestApp({ - url: `${makeChannelEditPath(channel.channel_type, channel.name)}/`, - }) - await screen.findByText("You do not have permission to access this page.") - const tabs = screen.queryAllByRole("tab") - expect(tabs.length).toEqual(0) - }) - - it("Displays the correct tab and form for the #appearance hash", async () => { - const channel = setup() - setMockResponse.get(apiUrls.userMe.get(), {}) - setMockResponse.get( - apiUrls.testimonials.list({ offerors: [channel.name] }), - channel, - ) - setMockResponse.get(apiUrls.testimonials.details(channel.id), channel) - renderTestApp({ - url: `${makeChannelEditPath(channel.channel_type, channel.name)}/#appearance`, - }) - await screen.findByLabelText("Description") - await screen.findByLabelText("Appearance") - }) -}) diff --git a/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.tsx b/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.tsx deleted file mode 100644 index d14a17596c..0000000000 --- a/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import React, { useCallback } from "react" -// import { useNavigate, useLocation, useParams } from "react-router" -import { useRouter, useLocation, useParams } from "next/navigation" -import Link from "next/link" -import { Container, TabList, Tab, TabContext, TabPanel } from "ol-components" - -import { GridColumn, GridContainer } from "@/components/GridLayout/GridLayout" -import { useChannelDetail } from "api/hooks/channels" -import EditChannelAppearanceForm from "./EditChannelAppearanceForm" -import { ChannelPageTemplate } from "./ChannelPageTemplate" -import MetaTags from "@/page-components/MetaTags/MetaTags" - -type RouteParams = { - channelType: string - name: string -} - -const keyFromHash = (hash: string) => { - const keys = ["appearance", "moderators"] - const match = keys.find((key) => `#${key}` === hash) - return match ?? "appearance" -} - -const EditChannelPage: React.FC = () => { - const { channelType, name } = useParams() - const router = useRouter() - const { hash } = useLocation() - const tabValue = keyFromHash(hash) - const channel = useChannelDetail(String(channelType), String(name)) - - const handleChange = useCallback( - (event: React.SyntheticEvent, newValue: string) => { - router.push({ hash: newValue }, { replace: true }) - }, - [navigate], - ) - - return channel.data ? ( - - - {channel.data.is_moderator ? ( - -
- - - - - - - - - - -
- - - - -
- -
-
- - Moderators placeholder - -
-
-
-
- ) : ( - - - -
- You do not have permission to access this page. -
-
-
-
- )} -
- ) : null -} - -export default EditChannelPage diff --git a/frontends/mit-learn/src/pages/ChannelPage/WidgetsList.test.tsx b/frontends/mit-learn/src/pages/ChannelPage/WidgetsList.test.tsx deleted file mode 100644 index 22dbc9aa33..0000000000 --- a/frontends/mit-learn/src/pages/ChannelPage/WidgetsList.test.tsx +++ /dev/null @@ -1,133 +0,0 @@ -/* Not used? - -import React from "react" -import { - renderWithProviders, - screen, - waitFor, - expectProps, - user, - expectLastProps, - setMockResponse, - ignoreError, -} from "../../test-utils" -import { Widget, WidgetsListEditable } from "ol-widgets" -import { makeWidgetListResponse } from "ol-widgets/src/factories" -import WidgetsList from "./WidgetsList" -import { urls } from "api/test-utils" -import { makeRequest } from "../../test-utils/mockAxios" - -jest.mock("ol-widgets", () => { - const actual = jest.requireActual("ol-widgets") - return { - __esModule: true, - ...actual, - Widget: jest.fn(actual.Widget), - WidgetsListEditable: jest.fn(actual.WidgetsListEditable), - } -}) -const spyWidget = jest.mocked(Widget) -const spyWidgetsListEditable = jest.mocked(WidgetsListEditable) - -const setupApis = ({ widgets = 3 } = {}) => { - const widgetsList = makeWidgetListResponse({}, { count: widgets }) - setMockResponse.get(urls.widgetLists.details(widgetsList.id), widgetsList) - return { widgetsList } -} - -describe("Viewing widgets with WidgetsList", () => { - test("Renders widgets", async () => { - /* Issue is in react-markdown v6.0.3. The package is now several versions ahead. We can remove this once we update - * https://github.com/remarkjs/react-markdown/blob/ce6c1a71c17280e753e54e919511cd8bafadf86e/src/react-markdown.js#L138 - / - const ignored = ignoreError( - "Support for defaultProps will be removed from function components in a future major release", - ) - - const { widgetsList } = setupApis({ widgets: 3 }) - renderWithProviders( - , - ) - - /** - * Check that widget components are still on-screen - / - const { widgets } = widgetsList - const w1 = await screen.findByRole("heading", { name: widgets[0].title }) - const w2 = await screen.findByRole("heading", { name: widgets[1].title }) - const w3 = await screen.findByRole("heading", { name: widgets[2].title }) - - const { DOCUMENT_POSITION_FOLLOWING } = Node - expect(w1.compareDocumentPosition(w2)).toBe(DOCUMENT_POSITION_FOLLOWING) - expect(w2.compareDocumentPosition(w3)).toBe(DOCUMENT_POSITION_FOLLOWING) - - /** - * Check that the Widget component was called with correct props - / - expectProps(spyWidget, { widget: widgets.at(-1) }) - expectProps(spyWidget, { widget: widgets.at(-2) }) - expectProps(spyWidget, { widget: widgets.at(-3) }) - - ignored.clear() - }) -}) - -describe("Editing widgets with WidgetsList", () => { - it("renders WidgetsListEditable with expected stuff", async () => { - const { widgetsList } = setupApis({ widgets: 3 }) - renderWithProviders( - , - ) - - /** - * Check that widget components are still on-screen - / - const { widgets } = widgetsList - await waitFor(() => { - screen.getByRole("heading", { name: widgets[0].title }) - screen.getByRole("heading", { name: widgets[1].title }) - screen.getByRole("heading", { name: widgets[2].title }) - }) - expectLastProps(spyWidgetsListEditable, { widgetsList }) - }) - - it("makes the expected API call when WidgetsListEditable is edited+submitted", async () => { - const { widgetsList } = setupApis({ widgets: 3 }) - renderWithProviders( - , - ) - const deleteBtns = await screen.findAllByRole("button", { name: /Delete/ }) - expect(deleteBtns.length).toBe(3) - await user.click(deleteBtns[0]) - const modified = { - ...widgetsList, - widgets: widgetsList.widgets.slice(1), - } - setMockResponse.patch(urls.widgetLists.details(widgetsList.id), modified) - await user.click(screen.getByRole("button", { name: "Done" })) - expect(makeRequest).toHaveBeenCalledWith( - "patch", - urls.widgetLists.details(widgetsList.id), - expect.objectContaining({ - widgets: modified.widgets, - }), - ) - }) - - it("Does not make an API call if widget list not edited", async () => { - const { widgetsList } = setupApis({ widgets: 3 }) - renderWithProviders( - , - ) - // Wait for the widgets to have loaded - const deleteBtns = await screen.findAllByRole("button", { name: /Delete/ }) - expect(deleteBtns.length).toBe(3) - // click done without an edit - const callCount = makeRequest.mock.calls.length - await user.click(await screen.findByRole("button", { name: "Done" })) - // call count should be same as before - expect(makeRequest).toHaveBeenCalledTimes(callCount) - }) -}) - -*/ diff --git a/frontends/mit-learn/src/pages/ChannelPage/WidgetsList.tsx b/frontends/mit-learn/src/pages/ChannelPage/WidgetsList.tsx deleted file mode 100644 index 6f2c27440a..0000000000 --- a/frontends/mit-learn/src/pages/ChannelPage/WidgetsList.tsx +++ /dev/null @@ -1,109 +0,0 @@ -/* Not used? - -import React, { useCallback } from "react" -import { - Widget, - WidgetsListEditable, - WidgetsListEditableProps, - WidgetDialogClasses, - AnonymousWidget, - WidgetListResponse, -} from "ol-widgets" -import { WidgetInstance } from "api/v0" -import { useMutateWidgetsList, useWidgetList } from "api/hooks/widget_lists" -import { styled } from "ol-components" - -interface WidgetsListProps { - isEditing: boolean - widgetListId: number - className?: string - onFinishEditing?: () => void -} - -const dialogClasses: WidgetDialogClasses = { - dialog: "ic-widget-editing-dialog", - field: "form-field", - error: "validation-message", - label: "field-label", - detail: "field-detail", - fieldGroup: "form-item", -} - -export const WidgetListStyles = styled.div` - .ic-widget { - .ol-markdown { - a { - word-break: break-word; - color: theme.$link-blue; - - &:hover { - text-decoration: underline; - } - } - } - - margin-bottom: 5px; - } - - .ic-widget-editing-header { - h4 { - margin-top: 0; - } - } -` - -const WidgetsList: React.FC = ({ - widgetListId, - isEditing, - onFinishEditing, - className, -}) => { - const widgetsQuery = useWidgetList(widgetListId) - const mutation = useMutateWidgetsList(widgetListId) - const widgets = widgetsQuery.data?.widgets ?? [] - const onSubmit: WidgetsListEditableProps["onSubmit"] = useCallback( - (event) => { - if (event.touched) { - mutation.mutate(event.widgets as WidgetInstance[], { - onSuccess: () => { - if (onFinishEditing) onFinishEditing() - }, - }) - } else { - if (onFinishEditing) onFinishEditing() - } - }, - [onFinishEditing, mutation], - ) - const onCancel: WidgetsListEditableProps["onCancel"] = useCallback(() => { - if (onFinishEditing) onFinishEditing() - }, [onFinishEditing]) - return ( - -
- {isEditing - ? widgetsQuery.data && ( - - ) - : widgets.map((widget) => ( - - ))} -
-
- ) -} - -export default WidgetsList -*/ diff --git a/frontends/mit-learn/src/routes.tsx b/frontends/mit-learn/src/routes.tsx deleted file mode 100644 index 0cef84e264..0000000000 --- a/frontends/mit-learn/src/routes.tsx +++ /dev/null @@ -1,208 +0,0 @@ -import React from "react" -import { RouteObject, Outlet } from "react-router" -import { ScrollRestoration } from "react-router-dom" - -import HomePage from "@/pages/HomePage/HomePage" -import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute" -import LearningPathListingPage from "@/pages/LearningPathListingPage/LearningPathListingPage" -import ChannelPage from "@/pages/ChannelPage/ChannelPage" -import EditChannelPage from "@/pages/ChannelPage/EditChannelPage" - -import ArticleDetailsPage from "@/pages/ArticleDetailsPage/ArticleDetailsPage" -import { ArticleCreatePage, ArticleEditPage } from "@/pages/ArticleUpsertPages" -import ProgramLetterPage from "@/pages/ProgramLetterPage/ProgramLetterPage" -import { DashboardPage } from "@/pages/DashboardPage/DashboardPage" -import { AboutPage } from "@/pages/AboutPage/AboutPage" -import PrivacyPage from "@/pages/PrivacyPage/PrivacyPage" -import TermsPage from "@/pages/TermsPage/TermsPage" -import ErrorPage from "@/pages/ErrorPage/ErrorPage" -import * as urls from "@/common/urls" -import Header from "@/page-components/Header/Header" -import Footer from "@/page-components/Footer/Footer" -import { Permissions } from "@/common/permissions" -import SearchPage from "./pages/SearchPage/SearchPage" -import LearningPathDetailsPage from "./pages/ListDetailsPage/LearningPathDetailsPage" -import LearningResourceDrawer from "./page-components/LearningResourceDrawer/LearningResourceDrawer" -import DepartmentListingPage from "./pages/DepartmentListingPage/DepartmentListingPage" -import TopicsListingPage from "./pages/TopicListingPage/TopicsListingPage" -import UnitsListingPage from "./pages/UnitsListingPage/UnitsListingPage" -import OnboardingPage from "./pages/OnboardingPage/OnboardingPage" -import CartPage from "./pages/EcommercePages/CartPage" - -import { styled } from "ol-components" - -const PageWrapper = styled.div({ - height: "calc(100vh - 80px)", - display: "flex", - flexDirection: "column", -}) - -const PageWrapperInner = styled.main({ - flex: "1", -}) - -const routes: RouteObject[] = [ - { - element: ( - <> - -
- - { - return location.pathname - }} - /> - - -