From 92980f7dbe7e6a5f9a25d6ac06e0db0d2846213a Mon Sep 17 00:00:00 2001 From: Ed Rivas Date: Thu, 9 Jun 2022 17:35:49 +0000 Subject: [PATCH 01/62] Blacken conf.py --- docs/conf.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index ee622e45b..238be3ddf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,18 +45,18 @@ master_doc = "index" # General information about the project. -project = u"Metecho" -copyright = u"2019–2020, Salesforce.org" -author = u"Salesforce.org" +project = "Metecho" +copyright = "2019–2020, Salesforce.org" +author = "Salesforce.org" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u"0.1.0" +version = "0.1.0" # The full version, including alpha/beta/rc tags. -release = u"0.1.0" +release = "0.1.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -126,8 +126,8 @@ ( master_doc, "Metecho.tex", - u"Metecho Documentation", - u"Salesforce.org", + "Metecho Documentation", + "Salesforce.org", "manual", ) ] @@ -137,7 +137,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "Metecho", u"Metecho Documentation", [author], 1)] +man_pages = [(master_doc, "Metecho", "Metecho Documentation", [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -149,7 +149,7 @@ ( master_doc, "Metecho", - u"Metecho Documentation", + "Metecho Documentation", author, "cookiecutterproject_name", """Web-based tool for collaborating on Salesforce projects""", From bb56941208093c5f4ac6ec31c98fe704bf4448d1 Mon Sep 17 00:00:00 2001 From: Ed Rivas Date: Thu, 9 Jun 2022 21:27:38 +0000 Subject: [PATCH 02/62] Convert docs to markdown --- .dockerignore | 2 +- AUTHORS.md | 3 + AUTHORS.rst | 5 - CHANGELOG.md | 1 + CHANGELOG.rst | 2 - CONTRIBUTING.md | 289 ++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.rst | 311 ------------------------------------------- README.md | 16 +++ README.rst | 26 ---- docs/api/index.md | 7 + docs/api/index.rst | 8 -- docs/conf.py | 5 +- docs/index.md | 14 ++ docs/index.rst | 21 --- requirements/dev.in | 1 + requirements/dev.txt | 18 +++ 16 files changed, 352 insertions(+), 377 deletions(-) create mode 100644 AUTHORS.md delete mode 100644 AUTHORS.rst create mode 100644 CHANGELOG.md delete mode 100644 CHANGELOG.rst create mode 100644 CONTRIBUTING.md delete mode 100644 CONTRIBUTING.rst create mode 100644 README.md delete mode 100644 README.rst create mode 100644 docs/api/index.md delete mode 100644 docs/api/index.rst create mode 100644 docs/index.md delete mode 100644 docs/index.rst diff --git a/.dockerignore b/.dockerignore index f62ba9d7f..aa2c6dde8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,7 +15,7 @@ **/*.orig **/*.pot **/*.py[cod] -**/*.rst +**/*.md **/*.sage.py **/*.spec **/*.sql diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 000000000..3b152b63d --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,3 @@ +# Credits + +Salesforce.org diff --git a/AUTHORS.rst b/AUTHORS.rst deleted file mode 100644 index b94d69f30..000000000 --- a/AUTHORS.rst +++ /dev/null @@ -1,5 +0,0 @@ -======= -Credits -======= - -Salesforce.org diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..825c32f0d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index a5693d973..000000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Changelog -========= diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..6981f6ff3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,289 @@ +# Development Setup + +## Cloning the project + + $ git clone git@github.com:SFDO-Tooling/Metecho + $ cd Metecho + +## Docker-based development + +1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop) and + make sure it is running. Ensure you\'re running `docker-compose` at least + version `1.25.2` to avoid container-abort bugs. The latest Docker Desktop + should come with this version or later. + +2. Create an `.env` file with the required environment variables: + + $ cp env.example .env + + Edit this file to change `DJANGO_SECRET_KEY` and `DJANGO_HASHID_SALT` to any + two different arbitrary string values. + + Next, run the following commands to generate a database encryption key: + + $ pip install cryptography + $ python + >>> from cryptography.fernet import Fernet + >>> Fernet.generate_key() + + This will output a bytestring, e.g. `b'mystring='`. Copy only the contents + of `'...'`, and add it to your `.env` file as `DB_ENCRYPTION_KEY`, e.g. + `DB_ENCRYPTION_KEY="mystring="`. + + To exit the Python shell, press `Ctrl-Z` and then `Enter` on Windows, or + `Ctrl-D` on OS X or Linux. Alternatively, you could also type the Python + command `exit()` and press `Enter`. + + Finally, set the following environment variables (if you\'re an OddBird, you + can find these values in the shared Keybase team folder \--`metecho/env`): + + DOCKER_SFDX_HUB_KEY=... + SFDX_CLIENT_ID=... + SFDX_CLIENT_SECRET=... + GITHUB_HOOK_SECRET=... + GITHUB_CLIENT_ID=... + GITHUB_CLIENT_SECRET=... + GITHUB_APP_ID=... + DOCKER_GITHUB_APP_KEY=... + + Note that none of the values should be quoted, and while + `DOCKER_SFDX_HUB_KEY` and `DOCKER_GITHUB_APP_KEY` are RSA private keys, they + must have newlines replaced with `\n` in order to work properly with the + Docker `env_file` configuration option (see + [this issue](https://github.com/moby/moby/issues/12997)). + +3. Run `./derrick build` to build/re-build all the container images. + +4. Run `./derrick up` to start the server(s). + +5. Visit in your browser. + +6. When you\'re done working on Metecho, `Ctrl-C` in the terminal where the + containers are running to exit. You can also `./derrick down` to stop all + running containers, or `./derrick prune` to clean up unused + images/containers. (`docker-compose ps` will tell you what containers are + currently running.) + +## Setting up the GitHub App + +To deploy this app, you will need to set up a GitHub App and give it proper +permissions. You can do that at +`https://github.com/organizations//settings/apps` + +The GitHub app lets users log into Metecho with their GitHub account, connect to +repositories, create branches, pull requests, and commit code. The app will need +the following permissions: + +- Repository permissions + - Contents: Read & write + - Metadata: Read-only + - Pull requests: Read & write + - Commit statuses: Read & write + - Workflows: Read & write +- Organization permissions: + - Members: Read-only +- User permissions: + - Email addresses: Read-only +- Subscribe to events: + - Pull request + - Pull request review + - Push + +If you want to allow Metecho to create new repositories in your organization, +you must grant access to the app to all repositories, not a subset of them, and +enable these additional permissions: + +- Repository permissions + - Administration: Read & write +- Organization permissions + - Members: Read & write + +To enable logging in with GitHub, set the \"User authorization callback URL\" to +`https:///accounts/github/login/callback/`, and be sure the +\"Request user authorization (OAuth) during installation\" box is checked. + +To enable GitHub webhooks, set the \"Webhook URL\" to +`https:///api/hook/`, and be sure the \"Active\" box is +checked and \"SSL verification\" is enabled. + +Use the \"Webhook secret\" value as your `GITHUB_HOOK_SECRET` environment +variable in Metecho. + +Use the app\'s \"App ID\" as `GITHUB_APP_ID`, \"Client ID\" as +`GITHUB_CLIENT_ID`, and \"Client secret\" as `GITHUB_CLIENT_SECRET`. + +Finally, generate a new private key for the app, replace newlines with `\n`, and +set it as the `DOCKER_GITHUB_APP_KEY` environment variable (the entire key, not +a path to one). + +### Logging in as a superuser + +First log in using your GitHub account. + +Then turn this user into a superuser using the `promote_superuser` command: + + $ docker-compose run --rm web python manage.py promote_superuser + +You will also need, when you log in, to make sure that the GitHub app that +provides Metecho with webhook updates and GitHub API access **is enabled for any +Organizations you are testing against**. By default it will only install for the +user you are logging in as. + +### GitHub Webhooks in Development + +To test GitHub webhooks in development, you will need to use the tool +[ngrok](https://ngrok.com/), which sets up a tunnel from the internet-at-large +to your computer. Run it like so: + + $ ngrok http --host-header=localhost:8080 8080 + +You will get output that indicates the name of the ngrok tunnel, which will look +like `https://.ngrok.io`. You will need to adjust the GitHub App to +point to the `/api/hook/` path of your ngrok tunnel (e.g. +`https://.ngrok.io/api/hook/`). This means that it\'s a +one-person-at-a-time thing, which is a problem for which we don\'t yet have a +solution. + +As an OddBird, you can access the app at +. + +## Setting up the database + +If your database has outdated sample data for development, remove it with: + + $ ./derrick truncate + +To populate the database with sample data for development, run: + + $ ./derrick truncate + $ ./derrick populate + +To allow automated emails to send with correct links, you\'ll need to set up the +default `Site` object in the Django admin. Assuming you\'ve already set your +user up as a superuser, go to +and set the \"Domain name\" field appropriately (to `localhost:8080`). If you +are setting up a deployed production or staging instance, set this value to the +domain from which you are serving that instance. + +## Docker development tasks + +Most tasks are defined in `derrick`; take a look in there and you will see you +can run e.g.: + + $ ./derrick up # start containers and servers + $ ./derrick down # shut down running containers + $ ./derrick build # rebuild all containers + $ ./derrick lint # format and lint JS, Sass, Python, etc + $ ./derrick test # run JS and Python tests + $ ./derrick test:py # run Python tests + $ ./derrick test:js # run JS tests + $ ./derrick test:js:watch # run JS tests and watches for changes + $ ./derrick add:js # add a yarn/npm package to dependencies + $ ./derrick lock:py # update requirements *.txt from *.in files + $ ./derrick migrate # run Django migrations + $ ./derrick migrations # add new Django migrations (``makemigrations``) + $ ./derrick messages # build messages for i18n + $ ./derrick schema # generate OpenAPI schema file + $ ./derrick shell # open Python shell + $ ./derrick prune # clean up unused Docker images and containers + $ ./derrick storybook # build storybook and run dev server + +To run any development tasks (such as changing Python or JS dependencies, or +generating or running migrations, or running a Django shell), you will need to +run them inside the Docker image. This takes the general form +`docker-compose run --no-deps web [command]`. In some cases, such as for +migrations or a Django shell, you will want to omit the `--no-deps` flag. + +You shouldn\'t need to run any other setup tasks; the Docker images will take +care of setting up a database and installing Python and JS dependencies for you. + +When you change Python or JS dependencies, you will need to rebuild the Docker +images, as we store dependencies in the images for speed: `./derrick build`. + +Docker caches each command in the [Dockerfile](Dockerfile) as its own layer. If +you change the Dockerfile, changing earlier layers will bust the cache on the +lower layers and make your next build slow again. + +## Docker development using VS Code + +Because front-end and back-end dependencies are installed in a Docker container +instead of locally, text editors that rely on locally-installed packages (e.g. +for code formatting/linting on save) need access to the running Docker +container. [VS Code](https://code.visualstudio.com/) supports this using the +[Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) +extension pack. + +Once you have the extension pack installed, when you open the Metecho folder in +VS Code, you will be prompted to `Reopen in Container`. Doing so will +effectively run `docker-compose up` and reload your window, now running inside +the Docker container. If you do not see the prompt, run the \"Remote-Containers: +Open Folder in Container\...\" command from the VS Code Command Palette to start +the Docker container. + +A number of project-specific VS Code extensions will be automatically installed +for you within the Docker container. See +[.devcontainer/devcontainer.json](.devcontainer/devcontainer.json) and +[.devcontainer/docker-compose.dev.yml](.devcontainer/docker-compose.dev.yml) for +Docker-specific VS Code settings. + +The first build will take a number of minutes, but subsequent builds will be +significantly faster. + +In contrast to `docker-compose up`, VS Code does not automatically run database +migrations or start the development server/watcher. To do so, open an +[integrated terminal](https://code.visualstudio.com/docs/editor/integrated-terminal) +in VS Code (`Ctrl-`\`) and use any of the development commands (this terminal +runs inside the Docker container): + + $ python manage.py migrate # run database migrations + $ yarn serve # start the development server/watcher + +For any commands, when using the VS Code integrated terminal inside the Docker +container, omit any `docker-compose run --rm web...` prefix, e.g.: + + $ python manage.py promote_superuser + $ yarn test:js + $ python manage.py truncate_data + $ python manage.py populate_data + +After running `yarn serve`, view the running app at in +your browser. + +For more detailed instructions and options, see the +[VS Code documentation](https://code.visualstudio.com/docs/remote/containers). + +## Internationalization + +To build and compile `.mo` and `.po` files for the back end, run: + + $ ./derrick messages + +For the front end, translation JSON files are served from `locales//` +directories, and the +[user language is auto-detected at runtime](https://github.com/i18next/i18next-browser-languageDetector). + +During development, strings are parsed automatically from the JS, and an English +translation file is auto-generated to `locales_dev/en/translation.json` on every +build. When this file changes, translations must be copied over to the +`locales/en/translation.json` file in order to have any effect. + +Strings with dynamic content (i.e. known only at runtime) cannot be +automatically parsed, but will log errors while the app is running if they\'re +missing from the served translation files. To resolve, add the missing key:value +translations to `locales//translation.json`. + +This applies to the server code too, except no error will be raised. Therefore, +you should use string literals everywhere in server-side code that might be +exposed to the front end, to properly generate translation files. See error +message handling in `metecho/api/sf_run_flow.py` for an example. + +## Storybook Development Workflow + +When doing development for the component library in Storybook, use one of these +two commands: + + $ ./derrick storybook # if running outside of container + $ yarn storybook # if working in a remote container in VS Code + +After running one of these commands, you can view the Storybook at + in your browser. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 16dab8564..000000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,311 +0,0 @@ -Development Setup -================= - -Cloning the project -------------------- - -:: - - $ git clone git@github.com:SFDO-Tooling/Metecho - $ cd Metecho - -Docker-based development ------------------------- - -1. Install `Docker Desktop`_ and make sure it is running. Ensure you're running - ``docker-compose`` at least version ``1.25.2`` to avoid container-abort bugs. - The latest Docker Desktop should come with this version or later. - -2. Create an ``.env`` file with the required environment variables:: - - $ cp env.example .env - - Edit this file to change ``DJANGO_SECRET_KEY`` and ``DJANGO_HASHID_SALT`` to - any two different arbitrary string values. - - Next, run the following commands to generate a database encryption key:: - - $ pip install cryptography - $ python - >>> from cryptography.fernet import Fernet - >>> Fernet.generate_key() - - This will output a bytestring, e.g. ``b'mystring='``. Copy only the contents - of ``'...'``, and add it to your ``.env`` file as ``DB_ENCRYPTION_KEY``, e.g. - ``DB_ENCRYPTION_KEY="mystring="``. - - To exit the Python shell, press ``Ctrl-Z`` and then ``Enter`` on Windows, or - ``Ctrl-D`` on OS X or Linux. Alternatively, you could also type the Python - command ``exit()`` and press ``Enter``. - - Finally, set the following environment variables (if you're an OddBird, you - can find these values in the shared Keybase team folder -- - ``metecho/env``):: - - DOCKER_SFDX_HUB_KEY=... - SFDX_CLIENT_ID=... - SFDX_CLIENT_SECRET=... - GITHUB_HOOK_SECRET=... - GITHUB_CLIENT_ID=... - GITHUB_CLIENT_SECRET=... - GITHUB_APP_ID=... - DOCKER_GITHUB_APP_KEY=... - - Note that none of the values should be quoted, and while - ``DOCKER_SFDX_HUB_KEY`` and ``DOCKER_GITHUB_APP_KEY`` are RSA private keys, - they must have newlines replaced with ``\n`` in order to work properly with - the Docker ``env_file`` configuration option (see `this issue`_). - -3. Run ``./derrick build`` to build/re-build all the container images. - -4. Run ``./derrick up`` to start the server(s). - -5. Visit ``_ in your browser. - -6. When you're done working on Metecho, ``Ctrl-C`` in the terminal where the - containers are running to exit. You can also ``./derrick down`` to stop - all running containers, or ``./derrick prune`` to clean up unused - images/containers. (``docker-compose ps`` will tell you what containers are - currently running.) - -.. _Docker Desktop: https://www.docker.com/products/docker-desktop -.. _this issue: https://github.com/moby/moby/issues/12997 - -Setting up the GitHub App -------------------------- - -To deploy this app, you will need to set up a GitHub App and give it proper -permissions. You can do that at -``https://github.com/organizations//settings/apps`` - -The GitHub app lets users log into Metecho with their GitHub account, connect to -repositories, create branches, pull requests, and commit code. The app will need -the following permissions: - -- Repository permissions - - Contents: Read & write - - Metadata: Read-only - - Pull requests: Read & write - - Commit statuses: Read & write - - Workflows: Read & write -- Organization permissions: - - Members: Read-only -- User permissions: - - Email addresses: Read-only -- Subscribe to events: - - Pull request - - Pull request review - - Push - -If you want to allow Metecho to create new repositories in your organization, -you must grant access to the app to all repositories, not a subset of them, and -enable these additional permissions: - -- Repository permissions - - Administration: Read & write -- Organization permissions - - Members: Read & write - -To enable logging in with GitHub, set the "User authorization callback URL" to -``https:///accounts/github/login/callback/``, and be sure the -"Request user authorization (OAuth) during installation" box is checked. - -To enable GitHub webhooks, set the "Webhook URL" to -``https:///api/hook/``, and be sure the "Active" box is -checked and "SSL verification" is enabled. - -Use the "Webhook secret" value as your ``GITHUB_HOOK_SECRET`` environment -variable in Metecho. - -Use the app's "App ID" as ``GITHUB_APP_ID``, "Client ID" as -``GITHUB_CLIENT_ID``, and "Client secret" as ``GITHUB_CLIENT_SECRET``. - -Finally, generate a new private key for the app, replace newlines with ``\n``, -and set it as the ``DOCKER_GITHUB_APP_KEY`` environment variable (the entire -key, not a path to one). - -Logging in as a superuser -~~~~~~~~~~~~~~~~~~~~~~~~~ - -First log in using your GitHub account. - -Then turn this user into a superuser using the ``promote_superuser`` command:: - - $ docker-compose run --rm web python manage.py promote_superuser - -You will also need, when you log in, to make sure that the GitHub app -that provides Metecho with webhook updates and GitHub API access **is -enabled for any Organizations you are testing against**. By default it -will only install for the user you are logging in as. - -GitHub Webhooks in Development -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To test GitHub webhooks in development, you will need to use the tool -`ngrok`_, which sets up a tunnel from the internet-at-large to your -computer. Run it like so:: - - $ ngrok http --host-header=localhost:8080 8080 - -You will get output that indicates the name of the ngrok tunnel, which will look -like ``https://.ngrok.io``. You will need to adjust the GitHub App to -point to the ``/api/hook/`` path of your ngrok tunnel (e.g. -``https://.ngrok.io/api/hook/``). This means that it's a -one-person-at-a-time thing, which is a problem for which we don't yet have -a solution. - -As an OddBird, you can access the app at -``_. - -.. _ngrok: https://ngrok.com/ - -Setting up the database ------------------------ - -If your database has outdated sample data for development, remove it with:: - - $ ./derrick truncate - -To populate the database with sample data for development, run:: - - $ ./derrick truncate - $ ./derrick populate - -To allow automated emails to send with correct links, you'll need to set up the -default ``Site`` object in the Django admin. Assuming you've already set your -user up as a superuser, go to -``_ and set the "Domain name" -field appropriately (to ``localhost:8080``). If you are setting up a deployed -production or staging instance, set this value to the domain from which you are -serving that instance. - -Docker development tasks ------------------------- - -Most tasks are defined in ``derrick``; take a look in there and you -will see you can run e.g.:: - - $ ./derrick up # start containers and servers - $ ./derrick down # shut down running containers - $ ./derrick build # rebuild all containers - $ ./derrick lint # format and lint JS, Sass, Python, etc - $ ./derrick test # run JS and Python tests - $ ./derrick test:py # run Python tests - $ ./derrick test:js # run JS tests - $ ./derrick test:js:watch # run JS tests and watches for changes - $ ./derrick add:js # add a yarn/npm package to dependencies - $ ./derrick lock:py # update requirements *.txt from *.in files - $ ./derrick migrate # run Django migrations - $ ./derrick migrations # add new Django migrations (``makemigrations``) - $ ./derrick messages # build messages for i18n - $ ./derrick schema # generate OpenAPI schema file - $ ./derrick shell # open Python shell - $ ./derrick prune # clean up unused Docker images and containers - $ ./derrick storybook # build storybook and run dev server - -To run any development tasks (such as changing Python or JS dependencies, or -generating or running migrations, or running a Django shell), you will need to -run them inside the Docker image. This takes the general form ``docker-compose -run --no-deps web [command]``. In some cases, such as for migrations or a Django -shell, you will want to omit the ``--no-deps`` flag. - -You shouldn't need to run any other setup tasks; the Docker images will take -care of setting up a database and installing Python and JS dependencies for you. - -When you change Python or JS dependencies, you will need to rebuild the Docker -images, as we store dependencies in the images for speed: ``./derrick -build``. - -Docker caches each command in the `Dockerfile `_ as its own layer. -If you change the Dockerfile, changing earlier layers will bust the cache on the -lower layers and make your next build slow again. - -Docker development using VS Code --------------------------------- - -Because front-end and back-end dependencies are installed in a Docker container -instead of locally, text editors that rely on locally-installed packages (e.g. -for code formatting/linting on save) need access to the running Docker -container. `VS Code`_ supports this using the `Remote Development`_ extension -pack. - -Once you have the extension pack installed, when you open the Metecho folder -in VS Code, you will be prompted to ``Reopen in Container``. Doing so will -effectively run ``docker-compose up`` and reload your window, now running inside -the Docker container. If you do not see the prompt, run the "Remote-Containers: -Open Folder in Container..." command from the VS Code Command Palette to start -the Docker container. - -A number of project-specific VS Code extensions will be automatically installed -for you within the Docker container. See `.devcontainer/devcontainer.json -<.devcontainer/devcontainer.json>`_ and `.devcontainer/docker-compose.dev.yml -<.devcontainer/docker-compose.dev.yml>`_ for Docker-specific VS Code settings. - -The first build will take a number of minutes, but subsequent builds will be -significantly faster. - -In contrast to ``docker-compose up``, VS Code does not automatically run -database migrations or start the development server/watcher. To do so, open an -`integrated terminal`_ in VS Code (``Ctrl-```) and use any of the development -commands (this terminal runs inside the Docker container):: - - $ python manage.py migrate # run database migrations - $ yarn serve # start the development server/watcher - -For any commands, when using the VS Code integrated terminal inside the -Docker container, omit any ``docker-compose run --rm web...`` prefix, e.g.:: - - $ python manage.py promote_superuser - $ yarn test:js - $ python manage.py truncate_data - $ python manage.py populate_data - -After running ``yarn serve``, view the running app at -``_ in your browser. - -For more detailed instructions and options, see the `VS Code documentation`_. - -.. _VS Code: https://code.visualstudio.com/ -.. _Remote Development: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack -.. _integrated terminal: https://code.visualstudio.com/docs/editor/integrated-terminal -.. _VS Code documentation: https://code.visualstudio.com/docs/remote/containers - -Internationalization --------------------- - -To build and compile ``.mo`` and ``.po`` files for the back end, run:: - - $ ./derrick messages - -For the front end, translation JSON files are served from -``locales//`` directories, and the `user language is auto-detected at -runtime`_. - -During development, strings are parsed automatically from the JS, and an English -translation file is auto-generated to ``locales_dev/en/translation.json`` on -every build. When this file changes, translations must be copied over to the -``locales/en/translation.json`` file in order to have any effect. - -Strings with dynamic content (i.e. known only at runtime) cannot be -automatically parsed, but will log errors while the app is running if they're -missing from the served translation files. To resolve, add the missing key:value -translations to ``locales//translation.json``. - -This applies to the server code too, except no error will be raised. Therefore, -you should use string literals everywhere in server-side code that might be -exposed to the front end, to properly generate translation files. See error -message handling in ``metecho/api/sf_run_flow.py`` for an example. - -.. _user language is auto-detected at runtime: https://github.com/i18next/i18next-browser-languageDetector - -Storybook Development Workflow ------------------------------- - -When doing development for the component library in Storybook, -use one of these two commands:: - - $ ./derrick storybook # if running outside of container - $ yarn storybook # if working in a remote container in VS Code - -After running one of these commands, you can view the Storybook at -``_ in your browser. diff --git a/README.md b/README.md new file mode 100644 index 000000000..cc702a8ef --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# Metecho + +[![Build Status](https://github.com/SFDO-Tooling/Metecho/actions/workflows/test.yml/badge.svg)](https://github.com/SFDO-Tooling/Metecho/actions/workflows/test.yml) + +[![Code Coverage](https://coveralls.io/repos/github/SFDO-Tooling/Metecho/badge.svg?branch=main)](https://coveralls.io/github/SFDO-Tooling/Metecho?branch=main) + +## Development + +[![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/SFDO-Tooling/metecho/tree/main) + +See [CONTRIBUTING.md](CONTRIBUTING.md). + +## Got feedback? + +Please open a new +[GitHub Issue](https://github.com/SFDO-Tooling/Metecho/issues). diff --git a/README.rst b/README.rst deleted file mode 100644 index 6033faaf2..000000000 --- a/README.rst +++ /dev/null @@ -1,26 +0,0 @@ -Metecho -======= - -.. image:: https://github.com/SFDO-Tooling/Metecho/actions/workflows/test.yml/badge.svg - :target: https://github.com/SFDO-Tooling/Metecho/actions/workflows/test.yml - :alt: Build Status - -.. image:: https://coveralls.io/repos/github/SFDO-Tooling/Metecho/badge.svg?branch=main - :target: https://coveralls.io/github/SFDO-Tooling/Metecho?branch=main - :alt: Code Coverage - - -Development ------------ - -.. image:: https://www.herokucdn.com/deploy/button.svg - :target: https://heroku.com/deploy?template=https://github.com/SFDO-Tooling/metecho/tree/main - :alt: Deploy to Heroku - -See `CONTRIBUTING.rst `_. - -Got feedback? -------------- - -Please open a new `GitHub Issue -`_. diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 000000000..9f57aab74 --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,7 @@ +# API Reference + +You can access automatically generated API documentation on any Metecho instance +by following these steps: + +- Set the environment variable `API_DOCS_ENABLED=true`. +- Visit `/api/schema/redoc/`. diff --git a/docs/api/index.rst b/docs/api/index.rst deleted file mode 100644 index 414b2387c..000000000 --- a/docs/api/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -API Reference -============= - -You can access automatically generated API documentation on any Metecho instance -by following these steps: - -- Set the environment variable `API_DOCS_ENABLED=true`. -- Visit `/api/schema/redoc/`. diff --git a/docs/conf.py b/docs/conf.py index 238be3ddf..f1cee1954 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -30,7 +30,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ["sphinx.ext.autodoc", "sphinxcontrib.httpdomain"] +extensions = ["sphinx.ext.autodoc", "sphinxcontrib.httpdomain", "myst_parser"] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -38,8 +38,7 @@ # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # -# source_suffix = ['.rst', '.md'] -source_suffix = ".rst" +source_suffix = [".rst", ".md"] # The main toctree document. master_doc = "index" diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..73de98433 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,14 @@ +# Welcome to Metecho's documentation! + +```{toctree} +:maxdepth: 2 +:caption: 'Contents:' + +api/index +``` + +# Indices and tables + +- {ref}`genindex` +- {ref}`modindex` +- {ref}`search` diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index acae44497..000000000 --- a/docs/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. Metecho documentation main file, created by - sphinx-quickstart on Sat May 20 12:05:20 2017. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Metecho's documentation! -=================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - api/index - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/requirements/dev.in b/requirements/dev.in index 3c7f47128..1c79134de 100644 --- a/requirements/dev.in +++ b/requirements/dev.in @@ -13,6 +13,7 @@ flake8 flake8-bugbear ipython isort +myst-parser pytest pytest-asyncio pytest-cov diff --git a/requirements/dev.txt b/requirements/dev.txt index 815d84f45..702e157bf 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -57,6 +57,7 @@ docutils==0.16 # via # -c requirements/prod.txt # doc8 + # myst-parser # restructuredtext-lint # sphinx executing==0.8.3 @@ -96,7 +97,12 @@ jedi==0.18.1 jinja2==2.11.3 # via # -c requirements/prod.txt + # myst-parser # sphinx +markdown-it-py==2.1.0 + # via + # mdit-py-plugins + # myst-parser markupsafe==2.0.1 # via # -c requirements/prod.txt @@ -105,8 +111,14 @@ matplotlib-inline==0.1.3 # via ipython mccabe==0.6.1 # via flake8 +mdit-py-plugins==0.3.0 + # via myst-parser +mdurl==0.1.1 + # via markdown-it-py mypy-extensions==0.4.3 # via black +myst-parser==0.18.0 + # via -r requirements/dev.in packaging==21.3 # via # -c requirements/prod.txt @@ -181,6 +193,10 @@ pytz==2022.1 # via # -c requirements/prod.txt # babel +pyyaml==6.0 + # via + # -c requirements/prod.txt + # myst-parser remote-pdb==2.1.0 # via -r requirements/dev.in requests==2.27.1 @@ -201,6 +217,7 @@ snowballstemmer==2.2.0 sphinx==5.0.1 # via # -r requirements/dev.in + # myst-parser # sphinxcontrib-httpdomain sphinxcontrib-applehelp==1.0.2 # via sphinx @@ -238,6 +255,7 @@ traitlets==5.2.2.post1 typing-extensions==4.2.0 # via # -c requirements/prod.txt + # myst-parser # pytest-factoryboy urllib3==1.26.9 # via From 8ad59b22e9274e4c20b9cb86bbf7ef504c8de32a Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Fri, 10 Jun 2022 09:56:40 -0400 Subject: [PATCH 03/62] Remove references to OddBird --- CONTRIBUTING.md | 6 +----- docs/conf.py | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6981f6ff3..223a0e41d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,8 +34,7 @@ `Ctrl-D` on OS X or Linux. Alternatively, you could also type the Python command `exit()` and press `Enter`. - Finally, set the following environment variables (if you\'re an OddBird, you - can find these values in the shared Keybase team folder \--`metecho/env`): + Finally, set the following environment variables: DOCKER_SFDX_HUB_KEY=... SFDX_CLIENT_ID=... @@ -144,9 +143,6 @@ point to the `/api/hook/` path of your ngrok tunnel (e.g. one-person-at-a-time thing, which is a problem for which we don\'t yet have a solution. -As an OddBird, you can access the app at -. - ## Setting up the database If your database has outdated sample data for development, remove it with: diff --git a/docs/conf.py b/docs/conf.py index f1cee1954..cdb165c2a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,7 +45,7 @@ # General information about the project. project = "Metecho" -copyright = "2019–2020, Salesforce.org" +copyright = "2019–2022, Salesforce.org" author = "Salesforce.org" # The version info for the project you're documenting, acts as replacement for From 8bc740adf422b6b3208aeed62eaa531c6606f449 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Thu, 19 May 2022 18:18:53 +0200 Subject: [PATCH 04/62] Deleting user account --- locales_dev/en/translation.json | 3 ++ metecho/urls.py | 2 +- src/js/components/user/delete.tsx | 44 +++++++++++++++ src/js/components/user/info.tsx | 2 + src/js/components/user/manage.tsx | 72 +++++++++++++++++++++++++ src/js/components/utils/deleteModal.tsx | 13 ++++- src/js/index.tsx | 2 + src/js/utils/routes.ts | 2 + test/js/components/user/info.test.jsx | 1 + 9 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/js/components/user/delete.tsx create mode 100644 src/js/components/user/manage.tsx diff --git a/locales_dev/en/translation.json b/locales_dev/en/translation.json index dd6b493ad..6371020cc 100644 --- a/locales_dev/en/translation.json +++ b/locales_dev/en/translation.json @@ -57,6 +57,7 @@ "Completed item": "Completed item", "Confirm": "Confirm", "Confirm Changing Developer and Deleting Dev Org": "Confirm Changing Developer and Deleting Dev Org", + "Confirm Deleting Account": "Confirm Deleting Account", "Confirm Deleting Epic": "Confirm Deleting Epic", "Confirm Deleting Org With Unretrieved Changes": "Confirm Deleting Org With Unretrieved Changes", "Confirm Deleting Task": "Confirm Deleting Task", @@ -186,6 +187,7 @@ "Make a Scratch Org to view the Project and play.": "Make a Scratch Org to view the Project and play.", "Make changes and retrieve them into a repository on GitHub.": "Make changes and retrieve them into a repository on GitHub.", "Make changes in Dev Org": "Make changes in Dev Org", + "Manage Account": "Manage Account", "Markdown Guide": "Markdown Guide", "Merge pull request on GitHub": "Merge pull request on GitHub", "Merged": "Merged", @@ -438,6 +440,7 @@ "check again": "check again", "confirmDeleteEpic": "Are you sure you want to delete Epic “<1>{{name}}”? This will also delete any Tasks and Orgs in this Epic.", "confirmDeleteTask": "Are you sure you want to delete Task “<1>{{name}}”? This will also delete any Orgs in this Task.", + "confirmDeleteUser": "Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Are you sure you want to delete your Metecho account?", "confirmRemoveCollaboratorsHeading": "Confirm Removing Collaborator", "confirmRemoveCollaboratorsHeading_plural": "Confirm Removing Collaborator", "confirmRemoveCollaboratorsMessage": "The following user is being removed from this Epic, but is already assigned to at least one Task. Removing this user will not remove them from any assigned Tasks. Are you sure you want to remove this user from the Epic?", diff --git a/metecho/urls.py b/metecho/urls.py index 772e62aac..ccea1f15f 100644 --- a/metecho/urls.py +++ b/metecho/urls.py @@ -40,7 +40,7 @@ # Routes to pass through to the front end JS route-handler # Ensure the CSRF token is always present via a cookie to be read by JS re_path( - r"^($|login\/?$|terms\/?$|projects(\/|$)|accounts(\/|$))", + r"^($|login\/?$|manage\/?$|terms\/?$|projects(\/|$)|accounts(\/|$))", ensure_csrf_cookie(TemplateView.as_view(template_name="index.html")), name="frontend", ), diff --git a/src/js/components/user/delete.tsx b/src/js/components/user/delete.tsx new file mode 100644 index 000000000..75e3f798f --- /dev/null +++ b/src/js/components/user/delete.tsx @@ -0,0 +1,44 @@ +import Button from '@salesforce/design-system-react/components/button'; +import React, { useState } from 'react'; +import { useSelector } from 'react-redux'; + +import { DeleteModal } from '@/js/components/utils'; +import { User } from '@/js/store/user/reducer'; +import { selectUserState } from '@/js/store/user/selectors'; +import { OBJECT_TYPES } from '@/js/utils/constants'; +import routes from '@/js/utils/routes'; + +const DeleteAccount = () => { + const [deleteModalOpen, setDeleteModalOpen] = useState(false); + const user = useSelector(selectUserState); + const closeDeleteModal = () => { + setDeleteModalOpen(false); + }; + const openDeleteModal = () => { + setDeleteModalOpen(true); + }; + return ( +
+
Delete Account
+
+ Deleting this account will not remove you as a Project collaborator on + Github. Your Dev Orgs will be deleted, and any unretrieved changes will + be lost. This action cannot be undone. +
+
+ ); +}; +export default DeleteAccount; diff --git a/src/js/components/user/info.tsx b/src/js/components/user/info.tsx index 3f92d2f5c..475bf5c76 100644 --- a/src/js/components/user/info.tsx +++ b/src/js/components/user/info.tsx @@ -11,6 +11,7 @@ import { useDispatch, useSelector } from 'react-redux'; import ConnectModal from '@/js/components/user/connect'; import Logout from '@/js/components/user/logout'; +import { ManageAccountButton } from '@/js/components/user/manage'; import { ExternalLink, SpinnerWrapper, @@ -285,6 +286,7 @@ const UserDropdown = () => { > {user.username} + diff --git a/src/js/components/user/manage.tsx b/src/js/components/user/manage.tsx new file mode 100644 index 000000000..f7c5494b7 --- /dev/null +++ b/src/js/components/user/manage.tsx @@ -0,0 +1,72 @@ +import BreadCrumb from '@salesforce/design-system-react/components/breadcrumb'; +import PageHeader from '@salesforce/design-system-react/components/page-header'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Link } from 'react-router-dom'; + +import routes from '@/js/utils/routes'; + +import DeleteAccount from './delete'; + +export const ManageAccountButton = () => { + const { t } = useTranslation(); + + return {t('Manage Account')}; +}; + +const Manage = () => { + const { t } = useTranslation(); + + return ( + <> +
+ + {t('Manage Account')} + + } + /> +
+
+
+ + {t('Home')} + , +
+ {t('Manage Account')} +
, + ]} + /> +
+
+
+
+
+ +
+
+
+ + ); +}; + +export default Manage; diff --git a/src/js/components/utils/deleteModal.tsx b/src/js/components/utils/deleteModal.tsx index 8125cb2ac..a5efadc45 100644 --- a/src/js/components/utils/deleteModal.tsx +++ b/src/js/components/utils/deleteModal.tsx @@ -10,10 +10,11 @@ import { ThunkDispatch } from '@/js/store'; import { deleteObject } from '@/js/store/actions'; import { Epic } from '@/js/store/epics/reducer'; import { Task } from '@/js/store/tasks/reducer'; +import { User } from '@/js/store/user/reducer'; import { OBJECT_TYPES, ObjectTypes } from '@/js/utils/constants'; interface Props extends RouteComponentProps { - model: Epic | Task; + model: Epic | Task | User; modelType: ObjectTypes; isOpen: boolean; redirect: string; @@ -73,6 +74,16 @@ const DeleteModal = ({ ); break; + case OBJECT_TYPES.USER: + heading = t('Confirm Deleting Account'); + message = ( + + Your Dev Orgs will be deleted, and any unretrieved changes will be + lost. This action cannot be undone. Are you sure you want to delete + your Metecho account? + + ); + break; } return ( diff --git a/src/js/index.tsx b/src/js/index.tsx index dcb419d14..2755b74d3 100644 --- a/src/js/index.tsx +++ b/src/js/index.tsx @@ -42,6 +42,7 @@ import TaskDetail from '@/js/components/tasks/detail'; import Terms from '@/js/components/terms'; import AuthError from '@/js/components/user/authError'; import Login from '@/js/components/user/login'; +import Manage from '@/js/components/user/manage'; import { PrivateRoute } from '@/js/components/utils'; import initializeI18n from '@/js/i18n'; import reducer, { ThunkDispatch } from '@/js/store'; @@ -92,6 +93,7 @@ const App = withRouter( + '/', login: () => '/login', + manage: () => '/manage', terms: () => '/terms', project_list: () => '/projects', project_detail: (projectSlug: string) => `/projects/${projectSlug}`, @@ -15,6 +16,7 @@ const routes = { export const routePatterns = { home: '/', login: '/login', + manage: '/manage', terms: '/terms', auth_error: '/accounts/*', project_list: '/projects', diff --git a/test/js/components/user/info.test.jsx b/test/js/components/user/info.test.jsx index eca324899..6cf83e809 100644 --- a/test/js/components/user/info.test.jsx +++ b/test/js/components/user/info.test.jsx @@ -74,6 +74,7 @@ describe('', () => { expect(getByText('Test User')).toBeVisible(); expect(getByText('Log Out')).toBeVisible(); + expect(getByText('Manage Account')).toBeVisible(); }); describe('not connected', () => { From 2ba789315a4f1b6752549460df94da62b64390bd Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Mon, 23 May 2022 17:27:21 +0200 Subject: [PATCH 05/62] Code review edits --- src/js/components/user/info.tsx | 2 +- src/js/components/user/manage.tsx | 74 ++++++++++++++----------------- src/js/index.tsx | 6 ++- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/js/components/user/info.tsx b/src/js/components/user/info.tsx index 475bf5c76..672b408a5 100644 --- a/src/js/components/user/info.tsx +++ b/src/js/components/user/info.tsx @@ -286,7 +286,7 @@ const UserDropdown = () => { > {user.username} - + diff --git a/src/js/components/user/manage.tsx b/src/js/components/user/manage.tsx index f7c5494b7..169f028b5 100644 --- a/src/js/components/user/manage.tsx +++ b/src/js/components/user/manage.tsx @@ -1,71 +1,65 @@ import BreadCrumb from '@salesforce/design-system-react/components/breadcrumb'; import PageHeader from '@salesforce/design-system-react/components/page-header'; import React from 'react'; +import DocumentTitle from 'react-document-title'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; +import DeleteAccount from '@/js/components/user/delete'; import routes from '@/js/utils/routes'; -import DeleteAccount from './delete'; - -export const ManageAccountButton = () => { +export const ManageAccountButton = (props: any) => { const { t } = useTranslation(); - return {t('Manage Account')}; + return ( + + {t('Manage Account')} + + ); }; const Manage = () => { const { t } = useTranslation(); return ( - <> -
- - {t('Manage Account')} - - } - /> -
+
-
+ +
+
+
- - {t('Home')} - , -
- {t('Manage Account')} -
, - ]} - /> + > + + {t('Home')} + , +
+ {t('Manage Account')} +
, + ]} + /> +
-
-
-
+
- +
- + ); }; diff --git a/src/js/index.tsx b/src/js/index.tsx index 2755b74d3..e50a2db77 100644 --- a/src/js/index.tsx +++ b/src/js/index.tsx @@ -93,7 +93,11 @@ const App = withRouter( - + Date: Tue, 31 May 2022 15:24:31 +0200 Subject: [PATCH 06/62] Backend for delete account --- docs/api/schema.yml | 20 ++++++++++++++ .../migrations/0109_alter_scratchorg_owner.py | 20 ++++++++++++++ metecho/api/models.py | 22 +++++++++++++++- metecho/api/views.py | 6 +++++ src/js/components/user/delete.tsx | 26 ++++++++++++++----- src/js/components/user/info.tsx | 4 +-- src/js/components/user/manage.tsx | 2 +- src/js/components/utils/deleteModal.tsx | 17 +++++++++--- src/js/store/actions.ts | 19 +++++++++----- src/js/utils/api.ts | 18 +++++++++++++ 10 files changed, 133 insertions(+), 21 deletions(-) create mode 100644 metecho/api/migrations/0109_alter_scratchorg_owner.py diff --git a/docs/api/schema.yml b/docs/api/schema.yml index 37d8597df..6fc8b5fc4 100644 --- a/docs/api/schema.yml +++ b/docs/api/schema.yml @@ -1323,6 +1323,26 @@ paths: schema: $ref: '#/components/schemas/FullUser' description: '' + /api/user/{id}/delete/: + delete: + operationId: user_delete_destroy + description: Actions related to the current user. + parameters: + - in: path + name: id + schema: + type: string + format: HashID + description: A unique integer value identifying this user. + required: true + tags: + - user + security: + - tokenAuth: [] + - cookieAuth: [] + responses: + '204': + description: No response body /api/user/agree_to_tos/: put: operationId: user_agree_to_tos_update diff --git a/metecho/api/migrations/0109_alter_scratchorg_owner.py b/metecho/api/migrations/0109_alter_scratchorg_owner.py new file mode 100644 index 000000000..4a5dc61d8 --- /dev/null +++ b/metecho/api/migrations/0109_alter_scratchorg_owner.py @@ -0,0 +1,20 @@ +# Generated by Django 4.0.4 on 2022-05-26 12:50 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0108_project_has_truncated_issues'), + ] + + operations = [ + migrations.AlterField( + model_name='scratchorg', + name='owner', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/metecho/api/models.py b/metecho/api/models.py index 8f9e7afc1..229889a3c 100644 --- a/metecho/api/models.py +++ b/metecho/api/models.py @@ -1,5 +1,6 @@ import html import logging +import traceback from contextlib import suppress from datetime import timedelta from typing import Dict, Iterable, Optional, Tuple @@ -216,6 +217,25 @@ def _get_org_property(self, key): except (AttributeError, KeyError, TypeError): return None + def delete(self, *args, **kwargs): + + try: + for scratch_org_to_delete in self.scratchorg_set.all(): + scratch_org_to_delete.owner = None + scratch_org_to_delete.save() + scratch_org_to_delete.queue_delete(originating_user_id=self.id) + except Exception as e: + async_to_sync(push.report_scratch_org_error)( + scratch_org_to_delete, + error=e, + type_="SCRATCH_ORG_DELETE_FAILED", + originating_user_id=self.id, + ) + tb = traceback.format_exc() + logger.error(tb) + raise + super().delete(*args, **kwargs) + @property def github_id(self) -> Optional[str]: try: @@ -1198,7 +1218,7 @@ class ScratchOrg( description = MarkdownField(blank=True, property_suffix="_markdown") org_type = StringField(choices=ScratchOrgType.choices) org_config_name = StringField() - owner = models.ForeignKey(User, on_delete=models.PROTECT) + owner = models.ForeignKey(User, on_delete=models.PROTECT, blank=True, null=True) last_modified_at = models.DateTimeField(null=True, blank=True) expires_at = models.DateTimeField(null=True, blank=True) latest_commit = StringField(blank=True) diff --git a/metecho/api/views.py b/metecho/api/views.py index 90dd573c9..4045e2047 100644 --- a/metecho/api/views.py +++ b/metecho/api/views.py @@ -205,6 +205,12 @@ def refresh_orgs(self, request): """Queue a job to refresh the user's list of GitHub organizations.""" request.user.queue_refresh_organizations() return Response(status=status.HTTP_202_ACCEPTED) + + @extend_schema(request=None) + @action(methods=["delete"], detail=True) + def delete(self, request, *args, **kwargs): + request.user.delete() + return Response(status=status.HTTP_204_NO_CONTENT) class UserViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet): diff --git a/src/js/components/user/delete.tsx b/src/js/components/user/delete.tsx index 75e3f798f..c8c27d35a 100644 --- a/src/js/components/user/delete.tsx +++ b/src/js/components/user/delete.tsx @@ -19,11 +19,13 @@ const DeleteAccount = () => { }; return (
-
Delete Account
-
- Deleting this account will not remove you as a Project collaborator on - Github. Your Dev Orgs will be deleted, and any unretrieved changes will - be lost. This action cannot be undone. +
+ Delete Account +
+
+ Your Dev Orgs will be deleted, and any unretrieved changes will be lost. + This action cannot be undone. Deleting this account will not remove you + as a Project collaborator on Github.
); }; diff --git a/src/js/components/user/info.tsx b/src/js/components/user/info.tsx index 672b408a5..34efb9620 100644 --- a/src/js/components/user/info.tsx +++ b/src/js/components/user/info.tsx @@ -286,8 +286,8 @@ const UserDropdown = () => { > {user.username} - - + +
diff --git a/src/js/components/user/manage.tsx b/src/js/components/user/manage.tsx index 169f028b5..abfc1217f 100644 --- a/src/js/components/user/manage.tsx +++ b/src/js/components/user/manage.tsx @@ -13,7 +13,7 @@ export const ManageAccountButton = (props: any) => { return ( - {t('Manage Account')} +

{t('Manage Account')}

); }; diff --git a/src/js/components/utils/deleteModal.tsx b/src/js/components/utils/deleteModal.tsx index a5efadc45..c544c3ce2 100644 --- a/src/js/components/utils/deleteModal.tsx +++ b/src/js/components/utils/deleteModal.tsx @@ -21,6 +21,14 @@ interface Props extends RouteComponentProps { handleClose: () => void; } +const getModelDeleteUrl = (modelType: ObjectTypes) => { + let deleteUrl; + if (modelType === 'user') { + deleteUrl = window.api_urls.current_user_detail(); + } + return deleteUrl; +}; + const DeleteModal = ({ model, modelType, @@ -40,6 +48,7 @@ const DeleteModal = ({ deleteObject({ objectType: modelType, object: model, + userDeleteUrl: getModelDeleteUrl(modelType), }), ) .then(() => { @@ -60,8 +69,8 @@ const DeleteModal = ({ heading = t('Confirm Deleting Epic'); message = ( - Are you sure you want to delete Epic “{{ name: model.name }}”? This - will also delete any Tasks and Orgs in this Epic. + Are you sure you want to delete Epic “{{ name: (model as Epic).name }} + ”? This will also delete any Tasks and Orgs in this Epic. ); break; @@ -69,8 +78,8 @@ const DeleteModal = ({ heading = t('Confirm Deleting Task'); message = ( - Are you sure you want to delete Task “{{ name: model.name }}”? This - will also delete any Orgs in this Task. + Are you sure you want to delete Task “{{ name: (model as Task).name }} + ”? This will also delete any Orgs in this Task. ); break; diff --git a/src/js/store/actions.ts b/src/js/store/actions.ts index aea8e684b..b8ee87f28 100644 --- a/src/js/store/actions.ts +++ b/src/js/store/actions.ts @@ -1,7 +1,7 @@ import { ThunkResult } from '@/js/store'; import { Epic } from '@/js/store/epics/reducer'; import { Task } from '@/js/store/tasks/reducer'; -import apiFetch, { addUrlParams } from '@/js/utils/api'; +import apiFetch, { addUrlParams, getDeleteObjectUrl } from '@/js/utils/api'; import { ObjectTypes } from '@/js/utils/constants'; interface CreateObjectPayload { @@ -70,7 +70,8 @@ interface DeleteObjectAction { type: | 'DELETE_OBJECT_STARTED' | 'DELETE_OBJECT_SUCCEEDED' - | 'DELETE_OBJECT_FAILED'; + | 'DELETE_OBJECT_FAILED' + | 'USER_LOGGED_OUT'; payload: { object: any } & CreateObjectPayload; } interface ObjectRemoved { @@ -294,17 +295,15 @@ export const deleteObject = objectType, object, shouldSubscribeToObject = false, + userDeleteUrl, }: { objectType: ObjectTypes; object: { id: string; [key: string]: any }; shouldSubscribeToObject?: boolean | ((obj: any) => boolean); + userDeleteUrl?: string | undefined; }): ThunkResult> => async (dispatch) => { - const urlFn = window.api_urls[`${objectType}_detail`]; - let baseUrl; - if (urlFn && object.id) { - baseUrl = urlFn(object.id); - } + const baseUrl = getDeleteObjectUrl(objectType, object.id, userDeleteUrl); dispatch({ type: 'DELETE_OBJECT_STARTED', payload: { objectType, url: baseUrl, object }, @@ -329,6 +328,12 @@ export const deleteObject = id: object.id, }); } + if (objectType === 'user') { + return dispatch({ + type: 'USER_LOGGED_OUT' as const, + payload: { objectType, url: baseUrl, object }, + }); + } return dispatch({ type: 'DELETE_OBJECT_SUCCEEDED' as const, payload: { objectType, url: baseUrl, object }, diff --git a/src/js/utils/api.ts b/src/js/utils/api.ts index 71c5c69e2..34a0c1635 100644 --- a/src/js/utils/api.ts +++ b/src/js/utils/api.ts @@ -5,6 +5,8 @@ import { ThunkDispatch } from 'redux-thunk'; import { addError } from '@/js/store/errors/actions'; import { logError } from '@/js/utils/logging'; +import { ObjectTypes } from './constants'; + interface UrlParams { [key: string]: string | number | boolean | undefined; } @@ -124,4 +126,20 @@ export const removeUrlParam = (key: string, search?: string) => { return params.toString(); }; +export const getDeleteObjectUrl = ( + objectType: ObjectTypes, + id: string, + userDeleteUrl: string | undefined, +) => { + if (userDeleteUrl) { + return userDeleteUrl; + } + const urlFn = window.api_urls[`${objectType}_detail`]; + let baseUrl; + if (urlFn && id) { + baseUrl = urlFn(id); + } + return baseUrl; +}; + export default apiFetch; From 165b3d6d69e22eeba5fb0d3e09e91c2b3447bfad Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Wed, 1 Jun 2022 20:08:42 +0200 Subject: [PATCH 07/62] Linter fix --- .../api/migrations/0109_alter_scratchorg_owner.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/metecho/api/migrations/0109_alter_scratchorg_owner.py b/metecho/api/migrations/0109_alter_scratchorg_owner.py index 4a5dc61d8..a5c7fcd6d 100644 --- a/metecho/api/migrations/0109_alter_scratchorg_owner.py +++ b/metecho/api/migrations/0109_alter_scratchorg_owner.py @@ -1,20 +1,25 @@ # Generated by Django 4.0.4 on 2022-05-26 12:50 +import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('api', '0108_project_has_truncated_issues'), + ("api", "0108_project_has_truncated_issues"), ] operations = [ migrations.AlterField( - model_name='scratchorg', - name='owner', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + model_name="scratchorg", + name="owner", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to=settings.AUTH_USER_MODEL, + ), ), ] From 7911aee0c904c7e5ce4a917eaf296f57c9baf3e4 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Thu, 2 Jun 2022 18:03:49 +0200 Subject: [PATCH 08/62] JS tests --- test/js/components/user/delete.test.jsx | 41 +++++++++++++++++++ test/js/components/user/manage.test.jsx | 37 +++++++++++++++++ test/js/components/utils/deleteModal.test.jsx | 24 +++++++++++ test/js/store/actions.test.js | 32 +++++++++++++++ test/js/utils/api.test.js | 27 ++++++++++++ 5 files changed, 161 insertions(+) create mode 100644 test/js/components/user/delete.test.jsx create mode 100644 test/js/components/user/manage.test.jsx diff --git a/test/js/components/user/delete.test.jsx b/test/js/components/user/delete.test.jsx new file mode 100644 index 000000000..b2fa3c9b3 --- /dev/null +++ b/test/js/components/user/delete.test.jsx @@ -0,0 +1,41 @@ +import { fireEvent } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; + +import DeleteAccount from '@/js/components/user/delete'; + +import { renderWithRedux, storeWithThunk } from '../../utils'; + +describe(' tests', () => { + const setup = ( + initialState = { + user: { username: 'Test User' }, + }, + ) => { + const result = renderWithRedux( + + + , + initialState, + storeWithThunk, + ); + + return result; + }; + + test('Delete Account button renders', () => { + const { getByRole } = setup(); + expect(getByRole('button', { name: 'Delete Account' })).toBeVisible(); + }); + + test('Delete Account modal renders', () => { + const { getByRole, getByText, getByTitle, queryByText } = setup(); + fireEvent.click(getByRole('button', { name: 'Delete Account' })); + + expect(getByText('Confirm Deleting Account')).toBeVisible(); + + fireEvent.click(getByTitle('Cancel')); + + expect(queryByText('Confirm Deleting Account')).toBeNull(); + }); +}); diff --git a/test/js/components/user/manage.test.jsx b/test/js/components/user/manage.test.jsx new file mode 100644 index 000000000..2b863649a --- /dev/null +++ b/test/js/components/user/manage.test.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; + +import Manage from '@/js/components/user/manage'; + +import { renderWithRedux, storeWithThunk } from '../../utils'; + +describe(' tests', () => { + const setup = ( + initialState = { + user: { username: 'Test User' }, + }, + ) => { + const result = renderWithRedux( + + + , + initialState, + storeWithThunk, + ); + + return result; + }; + + test('Manage Account heading renders', () => { + const { getByRole } = setup(); + expect( + getByRole('heading', { level: 1, name: 'Manage Account' }), + ).toBeVisible(); + }); + + test('Manage Account breadcrumb renders', () => { + const result = setup(); + const breadCrumb = result.container.querySelector('.slds-breadcrumb'); + expect(breadCrumb).toBeVisible(); + }); +}); diff --git a/test/js/components/utils/deleteModal.test.jsx b/test/js/components/utils/deleteModal.test.jsx index 77e6fb16f..429165ce0 100644 --- a/test/js/components/utils/deleteModal.test.jsx +++ b/test/js/components/utils/deleteModal.test.jsx @@ -4,6 +4,7 @@ import { StaticRouter } from 'react-router-dom'; import { DeleteModal } from '@/js/components/utils'; import { deleteObject } from '@/js/store/actions'; +import routes from '@/js/utils/routes'; import { renderWithRedux, storeWithThunk } from './../../utils'; @@ -61,4 +62,27 @@ describe('', () => { expect(context.action).toBe('PUSH'); expect(context.url).toBe('/foo'); }); + + test('deletes user and redirects', async () => { + const defaultUser = { id: '123' }; + const { findByText, getByText, context } = setup({ + model: defaultUser, + modelType: 'user', + redirect: routes.login(), + }); + + fireEvent.click(getByText('Delete')); + + expect.assertions(4); + await findByText('Deleting…'); + + expect(deleteObject).toHaveBeenCalledTimes(1); + expect(deleteObject).toHaveBeenCalledWith({ + objectType: 'user', + object: defaultUser, + userDeleteUrl: '/api/user/', + }); + expect(context.action).toBe('PUSH'); + expect(context.url).toBe('/login'); + }); }); diff --git a/test/js/store/actions.test.js b/test/js/store/actions.test.js index c8d370ede..631abac4e 100644 --- a/test/js/store/actions.test.js +++ b/test/js/store/actions.test.js @@ -604,6 +604,38 @@ describe('deleteObject', () => { }); }); + test('sends DELETE to api for user delete', () => { + const store = storeWithThunk({}); + const userUrl = '/api/user/'; + fetchMock.deleteOnce(userUrl, 204); + const userObjectPayload = { + objectType: 'user', + url: '/api/user/', + object: { id: '123' }, + }; + const started = { + type: 'DELETE_OBJECT_STARTED', + payload: userObjectPayload, + }; + const succeeded = { + type: 'USER_LOGGED_OUT', + payload: userObjectPayload, + }; + + expect.assertions(1); + return store + .dispatch( + actions.deleteObject({ + objectType: 'user', + object: { id: '123' }, + userDeleteUrl: userUrl, + }), + ) + .then(() => { + expect(store.getActions()).toEqual([started, succeeded]); + }); + }); + describe('with shouldSubscribeToObject', () => { let store, org; diff --git a/test/js/utils/api.test.js b/test/js/utils/api.test.js index 11f5f6e9d..f5cad0b73 100644 --- a/test/js/utils/api.test.js +++ b/test/js/utils/api.test.js @@ -3,6 +3,7 @@ import fetchMock from 'fetch-mock'; import { addError } from '@/js/store/errors/actions'; import apiFetch, { addUrlParams, + getDeleteObjectUrl, getUrlParam, removeUrlParam, } from '@/js/utils/api'; @@ -181,4 +182,30 @@ describe('removeUrlParam', () => { return expect(actual).toBe(expected); }); + + describe('getDeleteObjectUrl', () => { + test('returns correct url for user object type', () => { + const expected = '/api/user/'; + + const actual = getDeleteObjectUrl('user', '123', '/api/user/'); + + return expect(actual).toBe(expected); + }); + + test('returns correct url for task object type', () => { + const expected = '/api/tasks/123/'; + + const actual = getDeleteObjectUrl('task', '123'); + + return expect(actual).toBe(expected); + }); + + test('returns correct url for epic object type', () => { + const expected = '/api/epics/123/'; + + const actual = getDeleteObjectUrl('epic', '123'); + + return expect(actual).toBe(expected); + }); + }); }); From 84dcda8d4e2e9c443f84e3cd299cc1c86f22088f Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Fri, 3 Jun 2022 16:15:55 +0200 Subject: [PATCH 09/62] Backend tests --- ...wner.py => 0110_alter_scratchorg_owner.py} | 4 +-- metecho/api/models.py | 20 +++---------- metecho/api/tests/models.py | 29 +++++++++++++++++++ metecho/api/tests/views.py | 4 +++ metecho/api/views.py | 2 +- 5 files changed, 40 insertions(+), 19 deletions(-) rename metecho/api/migrations/{0109_alter_scratchorg_owner.py => 0110_alter_scratchorg_owner.py} (83%) diff --git a/metecho/api/migrations/0109_alter_scratchorg_owner.py b/metecho/api/migrations/0110_alter_scratchorg_owner.py similarity index 83% rename from metecho/api/migrations/0109_alter_scratchorg_owner.py rename to metecho/api/migrations/0110_alter_scratchorg_owner.py index a5c7fcd6d..8f7fc5a7e 100644 --- a/metecho/api/migrations/0109_alter_scratchorg_owner.py +++ b/metecho/api/migrations/0110_alter_scratchorg_owner.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0.4 on 2022-05-26 12:50 +# Generated by Django 4.0.4 on 2022-06-07 13:40 import django.db.models.deletion from django.conf import settings @@ -8,7 +8,7 @@ class Migration(migrations.Migration): dependencies = [ - ("api", "0108_project_has_truncated_issues"), + ("api", "0109_support_project_creation"), ] operations = [ diff --git a/metecho/api/models.py b/metecho/api/models.py index 229889a3c..ebd0caf3e 100644 --- a/metecho/api/models.py +++ b/metecho/api/models.py @@ -1,6 +1,5 @@ import html import logging -import traceback from contextlib import suppress from datetime import timedelta from typing import Dict, Iterable, Optional, Tuple @@ -218,22 +217,11 @@ def _get_org_property(self, key): return None def delete(self, *args, **kwargs): + for scratch_org_to_delete in self.scratchorg_set.all(): + scratch_org_to_delete.owner = None + scratch_org_to_delete.save() + scratch_org_to_delete.queue_delete(originating_user_id=self.id) - try: - for scratch_org_to_delete in self.scratchorg_set.all(): - scratch_org_to_delete.owner = None - scratch_org_to_delete.save() - scratch_org_to_delete.queue_delete(originating_user_id=self.id) - except Exception as e: - async_to_sync(push.report_scratch_org_error)( - scratch_org_to_delete, - error=e, - type_="SCRATCH_ORG_DELETE_FAILED", - originating_user_id=self.id, - ) - tb = traceback.format_exc() - logger.error(tb) - raise super().delete(*args, **kwargs) @property diff --git a/metecho/api/tests/models.py b/metecho/api/tests/models.py index f658e6397..fc0dc0c3e 100644 --- a/metecho/api/tests/models.py +++ b/metecho/api/tests/models.py @@ -777,6 +777,23 @@ def test_is_devhub_enabled__sf_error(self, user_factory, social_account_factory) get_devhub_api.return_value = client assert not user.is_devhub_enabled + def test_user_delete_triggers_scratch_org_delete( + self, user_factory, scratch_org_factory + ): + user = user_factory() + with ExitStack() as stack: + delete_scratch_org_job = stack.enter_context( + patch("metecho.api.jobs.delete_scratch_org_job") + ) + + scratch_org = scratch_org_factory(last_modified_at=now(), owner=user) + + assert user.scratchorg_set.first() == scratch_org + + user.delete() + + assert delete_scratch_org_job.delay.called + @pytest.mark.django_db class TestScratchOrg: @@ -842,6 +859,18 @@ def test_notify_delete(self, scratch_org_factory): assert async_to_sync.called + def test_delete_scratch_org_with_no_owner(self, scratch_org_factory): + with ExitStack() as stack: + delete_scratch_org_job = stack.enter_context( + patch("metecho.api.jobs.delete_scratch_org_job") + ) + + scratch_org = scratch_org_factory(last_modified_at=now()) + scratch_org.owner = None + scratch_org.save() + scratch_org.queue_delete(originating_user_id=None) + assert delete_scratch_org_job.delay.called + def test_get_unsaved_changes(self, scratch_org_factory): with ExitStack() as stack: get_unsaved_changes_job = stack.enter_context( diff --git a/metecho/api/tests/views.py b/metecho/api/tests/views.py index e00fa1d24..363b0dd62 100644 --- a/metecho/api/tests/views.py +++ b/metecho/api/tests/views.py @@ -246,6 +246,10 @@ def test_check_app_installation__no_permissions( len(data["messages"]) == 3 ), "Expected three error messages when permission checks fail" + def test_delete(self, client, mocker): + response = client.delete(reverse("current-user-detail")) + assert response.status_code == 204 + @pytest.mark.django_db class TestGitHubIssueViewset: diff --git a/metecho/api/views.py b/metecho/api/views.py index 4045e2047..d804497f2 100644 --- a/metecho/api/views.py +++ b/metecho/api/views.py @@ -205,7 +205,7 @@ def refresh_orgs(self, request): """Queue a job to refresh the user's list of GitHub organizations.""" request.user.queue_refresh_organizations() return Response(status=status.HTTP_202_ACCEPTED) - + @extend_schema(request=None) @action(methods=["delete"], detail=True) def delete(self, request, *args, **kwargs): From 21d7120e1a8b47edf44d9476ef109ab5f064cc1c Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Mon, 13 Jun 2022 15:48:00 +0200 Subject: [PATCH 10/62] Code review edits --- locales/en/translation.json | 5 +++++ locales_dev/en/translation.json | 2 ++ metecho/api/models.py | 5 ++++- metecho/api/tests/models.py | 32 ++++++++----------------------- metecho/api/tests/views.py | 2 ++ src/js/components/user/delete.tsx | 26 +++++++++---------------- src/js/store/orgs/reducer.ts | 2 +- 7 files changed, 31 insertions(+), 43 deletions(-) diff --git a/locales/en/translation.json b/locales/en/translation.json index 0fde49818..88b5855c5 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -57,6 +57,7 @@ "Completed item": "Completed item", "Confirm": "Confirm", "Confirm Changing Developer and Deleting Dev Org": "Confirm Changing Developer and Deleting Dev Org", + "Confirm Deleting Account": "Confirm Deleting Account", "Confirm Deleting Epic": "Confirm Deleting Epic", "Confirm Deleting Org With Unretrieved Changes": "Confirm Deleting Org With Unretrieved Changes", "Confirm Deleting Task": "Confirm Deleting Task", @@ -107,6 +108,7 @@ "Currently Assigned": "Currently Assigned", "Custom Domain": "Custom Domain", "Delete": "Delete", + "Delete Account": "Delete Account", "Delete Epic": "Delete Epic", "Delete Org": "Delete Org", "Delete Task": "Delete Task", @@ -186,6 +188,7 @@ "Make a Scratch Org to view the Project and play.": "Make a Scratch Org to view the Project and play.", "Make changes and retrieve them into a repository on GitHub.": "Make changes and retrieve them into a repository on GitHub.", "Make changes in Dev Org": "Make changes in Dev Org", + "Manage Account": "Manage Account", "Markdown Guide": "Markdown Guide", "Merge pull request on GitHub": "Merge pull request on GitHub", "Merged": "Merged", @@ -438,6 +441,7 @@ "check again": "check again", "confirmDeleteEpic": "Are you sure you want to delete Epic “<1>{{name}}”? This will also delete any Tasks and Orgs in this Epic.", "confirmDeleteTask": "Are you sure you want to delete Task “<1>{{name}}”? This will also delete any Orgs in this Task.", + "confirmDeleteUser": "Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Are you sure you want to delete your Metecho account?", "confirmRemoveCollaboratorsHeading": "Confirm Removing Collaborator", "confirmRemoveCollaboratorsHeading_plural": "Confirm Removing Collaborators", "confirmRemoveCollaboratorsMessage": "The following user is being removed from this Epic, but is already assigned to at least one Task. Removing this user will not remove them from any assigned Tasks. Are you sure you want to remove this user from the Epic?", @@ -450,6 +454,7 @@ "createProjectScratchOrgHelp": "<0>Visit an Epic or Task to create a Scratch Org from a work in progress.", "createScratchOrgContributeWarning": "<0><0>You will not be able to retrieve any changes made in this Scratch Org.", "createScratchOrgHelp": "<0>You are creating a Scratch Org for <1>{{type}} “<3>{{name}}.”<1>Your new Org will expire in 30 days.<1>You will be able to access your Org from this <4>{{type}} page.", + "deleteAccountChanges": "Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Deleting this account will not remove you as a Project collaborator on Github.", "devHubInfo": "Connection to a Salesforce Org with Dev Hub enabled is required to create a Dev, Test, or Scratch Org. Learn how to <2>create a Developer Edition Org and <6>enable Dev Hub.", "devHubNotEnabled": "This Salesforce Org does not have Dev Hub enabled or your user does not have permission to create Dev, Test, or Scratch Orgs. Learn how to <2>enable Dev Hub.", "epicCollaborators": "Only users who have access to the GitHub repository for this Epic will appear in the list below. Visit GitHub to invite additional Collaborators.", diff --git a/locales_dev/en/translation.json b/locales_dev/en/translation.json index 6371020cc..167d22407 100644 --- a/locales_dev/en/translation.json +++ b/locales_dev/en/translation.json @@ -108,6 +108,7 @@ "Currently Assigned": "Currently Assigned", "Custom Domain": "Custom Domain", "Delete": "Delete", + "Delete Account": "Delete Account", "Delete Epic": "Delete Epic", "Delete Org": "Delete Org", "Delete Task": "Delete Task", @@ -453,6 +454,7 @@ "createProjectScratchOrgHelp": "<0>Visit an Epic or Task to create a Scratch Org from a work in progress.", "createScratchOrgContributeWarning": "<0><0>You will not be able to retrieve any changes made in this Scratch Org.", "createScratchOrgHelp": "<0>You are creating a Scratch Org for <1>{{type}} “<3>{{name}}.”<1>Your new Org will expire in 30 days.<1>You will be able to access your Org from this <4>{{type}} page.", + "deleteAccountChanges": "Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Deleting this account will not remove you as a Project collaborator on Github.", "devHubInfo": "Connection to a Salesforce Org with Dev Hub enabled is required to create a Dev, Test, or Scratch Org. Learn how to <2>create a Developer Edition Org and <6>enable Dev Hub.", "devHubNotEnabled": "This Salesforce Org does not have Dev Hub enabled or your user does not have permission to create Dev, Test, or Scratch Orgs. Learn how to <2>enable Dev Hub.", "epicCollaborators": "Only users who have access to the GitHub repository for this Epic will appear in the list below. Visit GitHub to invite additional Collaborators.", diff --git a/metecho/api/models.py b/metecho/api/models.py index ebd0caf3e..7a3af8cab 100644 --- a/metecho/api/models.py +++ b/metecho/api/models.py @@ -219,6 +219,9 @@ def _get_org_property(self, key): def delete(self, *args, **kwargs): for scratch_org_to_delete in self.scratchorg_set.all(): scratch_org_to_delete.owner = None + scratch_org_to_delete.owner_sf_username = "" + scratch_org_to_delete.owner_gh_username = "" + scratch_org_to_delete.owner_gh_id = "" scratch_org_to_delete.save() scratch_org_to_delete.queue_delete(originating_user_id=self.id) @@ -1273,7 +1276,7 @@ def save(self, *args, **kwargs): self.clean_config() ret = super().save(*args, **kwargs) - if is_new: + if is_new and self.owner: self.queue_provision(originating_user_id=str(self.owner.id)) self.notify_org_provisioning(originating_user_id=str(self.owner.id)) diff --git a/metecho/api/tests/models.py b/metecho/api/tests/models.py index fc0dc0c3e..1062de75a 100644 --- a/metecho/api/tests/models.py +++ b/metecho/api/tests/models.py @@ -778,21 +778,17 @@ def test_is_devhub_enabled__sf_error(self, user_factory, social_account_factory) assert not user.is_devhub_enabled def test_user_delete_triggers_scratch_org_delete( - self, user_factory, scratch_org_factory + self, mocker, user_factory, scratch_org_factory ): - user = user_factory() - with ExitStack() as stack: - delete_scratch_org_job = stack.enter_context( - patch("metecho.api.jobs.delete_scratch_org_job") - ) + mocker.patch("metecho.api.admin.gh") + scratch_org_delete_job = mocker.patch("metecho.api.jobs.delete_scratch_org_job") - scratch_org = scratch_org_factory(last_modified_at=now(), owner=user) - - assert user.scratchorg_set.first() == scratch_org - - user.delete() + user = user_factory() + scratch_org = scratch_org_factory(last_modified_at=now(), owner=user) + assert user.scratchorg_set.first() == scratch_org - assert delete_scratch_org_job.delay.called + user.delete() + assert scratch_org_delete_job.delay.called @pytest.mark.django_db @@ -859,18 +855,6 @@ def test_notify_delete(self, scratch_org_factory): assert async_to_sync.called - def test_delete_scratch_org_with_no_owner(self, scratch_org_factory): - with ExitStack() as stack: - delete_scratch_org_job = stack.enter_context( - patch("metecho.api.jobs.delete_scratch_org_job") - ) - - scratch_org = scratch_org_factory(last_modified_at=now()) - scratch_org.owner = None - scratch_org.save() - scratch_org.queue_delete(originating_user_id=None) - assert delete_scratch_org_job.delay.called - def test_get_unsaved_changes(self, scratch_org_factory): with ExitStack() as stack: get_unsaved_changes_job = stack.enter_context( diff --git a/metecho/api/tests/views.py b/metecho/api/tests/views.py index 363b0dd62..e0891b6f8 100644 --- a/metecho/api/tests/views.py +++ b/metecho/api/tests/views.py @@ -249,6 +249,8 @@ def test_check_app_installation__no_permissions( def test_delete(self, client, mocker): response = client.delete(reverse("current-user-detail")) assert response.status_code == 204 + with pytest.raises(client.user.DoesNotExist): + client.user.refresh_from_db() @pytest.mark.django_db diff --git a/src/js/components/user/delete.tsx b/src/js/components/user/delete.tsx index c8c27d35a..20b6bee9b 100644 --- a/src/js/components/user/delete.tsx +++ b/src/js/components/user/delete.tsx @@ -1,5 +1,6 @@ import Button from '@salesforce/design-system-react/components/button'; import React, { useState } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { DeleteModal } from '@/js/components/utils'; @@ -17,19 +18,22 @@ const DeleteAccount = () => { const openDeleteModal = () => { setDeleteModalOpen(true); }; + const { t } = useTranslation(); return (
- Delete Account + {t('Delete Account')}
- Your Dev Orgs will be deleted, and any unretrieved changes will be lost. - This action cannot be undone. Deleting this account will not remove you - as a Project collaborator on Github. + + Your Dev Orgs will be deleted, and any unretrieved changes will be + lost. This action cannot be undone. Deleting this account will not + remove you as a Project collaborator on Github. +
); }; diff --git a/src/js/store/orgs/reducer.ts b/src/js/store/orgs/reducer.ts index 4d7dbf86c..80796043c 100644 --- a/src/js/store/orgs/reducer.ts +++ b/src/js/store/orgs/reducer.ts @@ -19,7 +19,7 @@ export interface MinimalOrg { } export interface Org extends MinimalOrg { - owner: string; + owner: string | null; owner_gh_username: string; owner_gh_id: string | null; description: string; From 6f075d0e46c770f78a9f8b75cc0c3ac8efb797af Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Mon, 13 Jun 2022 10:55:32 -0400 Subject: [PATCH 11/62] adjust dropdown slightly --- src/js/components/user/info.tsx | 6 ++++-- src/js/components/user/manage.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/js/components/user/info.tsx b/src/js/components/user/info.tsx index 34efb9620..d252f5493 100644 --- a/src/js/components/user/info.tsx +++ b/src/js/components/user/info.tsx @@ -286,8 +286,10 @@ const UserDropdown = () => { > {user.username} - - +
+ +
+ diff --git a/src/js/components/user/manage.tsx b/src/js/components/user/manage.tsx index abfc1217f..169f028b5 100644 --- a/src/js/components/user/manage.tsx +++ b/src/js/components/user/manage.tsx @@ -13,7 +13,7 @@ export const ManageAccountButton = (props: any) => { return ( -

{t('Manage Account')}

+ {t('Manage Account')} ); }; From 4af9275a9123962774adcf892c2622b878e39f4a Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Mon, 13 Jun 2022 11:19:07 -0400 Subject: [PATCH 12/62] minor review --- locales/en/translation.json | 2 +- locales_dev/en/translation.json | 2 +- src/js/components/user/delete.tsx | 5 +++-- src/js/components/user/manage.tsx | 11 +++++------ src/js/utils/api.ts | 3 +-- test/js/components/user/delete.test.jsx | 1 + test/js/components/user/manage.test.jsx | 2 ++ 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/locales/en/translation.json b/locales/en/translation.json index 88b5855c5..e7c94d323 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -454,7 +454,7 @@ "createProjectScratchOrgHelp": "<0>Visit an Epic or Task to create a Scratch Org from a work in progress.", "createScratchOrgContributeWarning": "<0><0>You will not be able to retrieve any changes made in this Scratch Org.", "createScratchOrgHelp": "<0>You are creating a Scratch Org for <1>{{type}} “<3>{{name}}.”<1>Your new Org will expire in 30 days.<1>You will be able to access your Org from this <4>{{type}} page.", - "deleteAccountChanges": "Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Deleting this account will not remove you as a Project collaborator on Github.", + "deleteAccountChanges": "Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Deleting this account will not remove you as a Project collaborator on GitHub.", "devHubInfo": "Connection to a Salesforce Org with Dev Hub enabled is required to create a Dev, Test, or Scratch Org. Learn how to <2>create a Developer Edition Org and <6>enable Dev Hub.", "devHubNotEnabled": "This Salesforce Org does not have Dev Hub enabled or your user does not have permission to create Dev, Test, or Scratch Orgs. Learn how to <2>enable Dev Hub.", "epicCollaborators": "Only users who have access to the GitHub repository for this Epic will appear in the list below. Visit GitHub to invite additional Collaborators.", diff --git a/locales_dev/en/translation.json b/locales_dev/en/translation.json index 167d22407..22fa5f089 100644 --- a/locales_dev/en/translation.json +++ b/locales_dev/en/translation.json @@ -454,7 +454,7 @@ "createProjectScratchOrgHelp": "<0>Visit an Epic or Task to create a Scratch Org from a work in progress.", "createScratchOrgContributeWarning": "<0><0>You will not be able to retrieve any changes made in this Scratch Org.", "createScratchOrgHelp": "<0>You are creating a Scratch Org for <1>{{type}} “<3>{{name}}.”<1>Your new Org will expire in 30 days.<1>You will be able to access your Org from this <4>{{type}} page.", - "deleteAccountChanges": "Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Deleting this account will not remove you as a Project collaborator on Github.", + "deleteAccountChanges": "Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Deleting this account will not remove you as a Project collaborator on GitHub.", "devHubInfo": "Connection to a Salesforce Org with Dev Hub enabled is required to create a Dev, Test, or Scratch Org. Learn how to <2>create a Developer Edition Org and <6>enable Dev Hub.", "devHubNotEnabled": "This Salesforce Org does not have Dev Hub enabled or your user does not have permission to create Dev, Test, or Scratch Orgs. Learn how to <2>enable Dev Hub.", "epicCollaborators": "Only users who have access to the GitHub repository for this Epic will appear in the list below. Visit GitHub to invite additional Collaborators.", diff --git a/src/js/components/user/delete.tsx b/src/js/components/user/delete.tsx index 20b6bee9b..33a9de004 100644 --- a/src/js/components/user/delete.tsx +++ b/src/js/components/user/delete.tsx @@ -19,6 +19,7 @@ const DeleteAccount = () => { setDeleteModalOpen(true); }; const { t } = useTranslation(); + return (
@@ -28,11 +29,10 @@ const DeleteAccount = () => { Your Dev Orgs will be deleted, and any unretrieved changes will be lost. This action cannot be undone. Deleting this account will not - remove you as a Project collaborator on Github. + remove you as a Project collaborator on GitHub.
); }; + export default DeleteAccount; diff --git a/src/js/components/user/manage.tsx b/src/js/components/user/manage.tsx index 169f028b5..32261ea39 100644 --- a/src/js/components/user/manage.tsx +++ b/src/js/components/user/manage.tsx @@ -33,8 +33,8 @@ const Manage = () => {
{
diff --git a/src/js/utils/api.ts b/src/js/utils/api.ts index 34a0c1635..e2ae2af3c 100644 --- a/src/js/utils/api.ts +++ b/src/js/utils/api.ts @@ -3,10 +3,9 @@ import { isUndefined } from 'lodash'; import { ThunkDispatch } from 'redux-thunk'; import { addError } from '@/js/store/errors/actions'; +import { ObjectTypes } from '@/js/utils/constants'; import { logError } from '@/js/utils/logging'; -import { ObjectTypes } from './constants'; - interface UrlParams { [key: string]: string | number | boolean | undefined; } diff --git a/test/js/components/user/delete.test.jsx b/test/js/components/user/delete.test.jsx index b2fa3c9b3..0276f1504 100644 --- a/test/js/components/user/delete.test.jsx +++ b/test/js/components/user/delete.test.jsx @@ -25,6 +25,7 @@ describe(' tests', () => { test('Delete Account button renders', () => { const { getByRole } = setup(); + expect(getByRole('button', { name: 'Delete Account' })).toBeVisible(); }); diff --git a/test/js/components/user/manage.test.jsx b/test/js/components/user/manage.test.jsx index 2b863649a..b1ae47ee2 100644 --- a/test/js/components/user/manage.test.jsx +++ b/test/js/components/user/manage.test.jsx @@ -24,6 +24,7 @@ describe(' tests', () => { test('Manage Account heading renders', () => { const { getByRole } = setup(); + expect( getByRole('heading', { level: 1, name: 'Manage Account' }), ).toBeVisible(); @@ -32,6 +33,7 @@ describe(' tests', () => { test('Manage Account breadcrumb renders', () => { const result = setup(); const breadCrumb = result.container.querySelector('.slds-breadcrumb'); + expect(breadCrumb).toBeVisible(); }); }); From f48d9fe2a811558bf3c610da2ca446bbcb46261e Mon Sep 17 00:00:00 2001 From: Sondra Date: Mon, 13 Jun 2022 14:17:27 -0600 Subject: [PATCH 13/62] Create metecho-how-to added the how-to text --- docs/metecho-how-to | 135 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 docs/metecho-how-to diff --git a/docs/metecho-how-to b/docs/metecho-how-to new file mode 100644 index 000000000..0b3523584 --- /dev/null +++ b/docs/metecho-how-to @@ -0,0 +1,135 @@ +# Steps to Guide a Team Through Metecho + +Step 0 - Log in with GitHub +Create a GitHub account, if you don’t yet have one. +Contact an admin for the repository (e.g. Nonprofit Success Pack) on GitHub and ensure that you and anyone you’d like to work with are collaborators. + +(If you want to create a project, skip down to Create a Project.) +Step 1 - Select a Project +Project - (e.g. Nonprofit Success Pack) Projects contain all the work being done. They are equivalent to GitHub repositories. + +Select the Project you want to contribute to. +If you do not see the Project you want to work on: +Confirm that you are logged into the correct Metecho account. +Contact an admin for the repository on GitHub and ensure that you are a collaborator. +Select Re-sync Projects in Metecho. + +(To continue, go to Step 2 - Create a Task/s or, if you have a set of several closely related Tasks in mind, skip to Step 13 - Create an Epic.) + +Step 2 - Create a Task/s +Task - Tasks represent small changes to the Project, and may stand alone or be part of an Epic. Creating a Task creates a branch in GitHub. + +Select the Tasks tab. +Create a new Task of your own (or from an existing GitHub Issue). +Name the Task. +The name can be a brief description of the work. +Use the optional description section for more detail, if needed. +Use the recommended dev org type unless you know of a specific reason to use a different one. +Select Create to save and navigate to your Task detail view. Select Create & New to continue creating multiple Tasks that are unrelated to each other. +If you need to edit the Task name or description, or delete the Task, select the gear icon in the top right corner. Deleting a Task deletes all the Orgs as well. +Step 3 - Invite Task Developer/s +Developer - The person invited to do the work of a Task. + +Assign yourself or invite another person to be the Developer for each Task you created. +Invited Developers will see an alert in Metecho and receive an email invitation. They need to accept the invitation if they want to begin development on the Task. +If you do not see the person you want to invite, contact an admin for the repository on GitHub and ensure that the person is a collaborator. Then re-sync GitHub collaborators in Metecho. +If you need to change or remove the Task Developer, use the drop down menu on the Developer card in the Task detail view. +Step 4 - Create Dev Org +Dev Org - A temporary Salesforce org where a Developer can work on contributions to a Project. Dev Orgs expire after 30 days, and all unretrieved work is deleted. + +Review the Next Steps for This Task list to see progress and who is responsible for the next step. +To begin work, the Developer will need to select Create Org in the Dev Org card. +Dev Org creation can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the Dev Org is ready. +Step 5 - Make Changes in Dev Org +This step takes place in the new Salesforce Dev Org, not in Metecho. +Select View Org on the Dev Org card to navigate out of Metecho and make your changes in the temporary Salesforce Dev Org. +Step 6 - Retrieve Changes from Dev Org +Retrieve Changes - Pull the work you did in your Salesforce Dev Org into Metecho so that other people can review it. Developers may retrieve changes as many times as they like while they are working. + +When the Developer is ready to pull the Salesforce Dev Org work into Metecho, they need to select Check for Unretrieved Changes (button located just above the Developer card in the Task detail view). +Select the location to retrieve changes. +Use the preselected Package Directory unless you know of a specific reason to select a different option. +Select the changes to retrieve (or ignore). +Create a commit message that briefly describes the changes. +Select Retrieve Selected Changes. +Retrieving changes can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the changes have been retrieved. +Note that the Developer, commit message, and date now appear in a Commit History list in the Task detail view. +Step 7 - Submit Task Changes for Testing +Submit Changes - Document all the changes a Developer made in a Salesforce Dev Org so that a Tester can test the work and leave a review. This action creates a pull request in GitHub. +Pull Request - A way to propose changes on GitHub so that the maintainers of a Project can review them and accept the changes or request revisions. + +When the Developer is finished working and retrieving changes, they need to select Submit Task for Testing (button located just above the Developer card in the Task detail view). +Each commit message briefly described what changed. Now, when submitting the Task for testing, describe all the critical changes and why they were made so the Tester will understand how to test them. +Select Submit Task for Testing. +Step 8 - Invite a Tester +Tester - The person who will look at the Developer’s work, and then approve the work or request changes that must be addressed before the Task can be completed. + +Assign yourself or invite another person to be the Tester for each Task you created. +Testers can be invited at any time and, just like Developers, they need to accept the invitation in order to begin testing. +If you do not see the person you want to invite, contact an admin for the repository on GitHub and ensure that the person is a collaborator. Then re-sync GitHub collaborators in Metecho. +If you need to change or remove the Task Tester, use the drop down menu on the Tester card in the Task detail view. +Step 9 - Create Test Org +Test Org - A temporary Salesforce org where the Tester can look over the Developer’s work on a specific Task. Test Orgs expire after 30 days. + +Remember, you can review the Next Steps for This Task list to see progress and who is responsible for the next step. +To begin testing, a Task Tester will need to select Create Org in the Test Org card. +Dev Org creation can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the Dev Org is ready. +Step 10 - Test Changes in Test Org +This step takes place in the new Salesforce Test Org, not in Metecho. +Select View Org on the Test Org card to navigate out of Metecho and test the Developer’s changes in the temporary Salesforce Test Org. +Step 11 - Submit a Review +When the Tester is finished testing the Developer’s changes in the Test Org, select Submit Review on the Test Org card. +Select Approve if no more work is needed. +Select Request Changes if the Developer needs to make revisions. +Leave a description, especially if there are still changes the Developer needs to make, so that the Developer understands what to do next. +Leaving Delete Test Org checked makes sense in most cases. +If the changes are Approved, there is no longer any need for the Test Org. +If the Developer needs to make changes, the Tester will need to create a new Test Org to see the newly retrieved changes. +Select Submit Review. +If any change needs to be made to the review, select Update Review in the Test Org card. +Step 12 - Merge Pull Request on GitHub +Merge - To add proposed changes to the Project on GitHub. + +This step takes place on GitHub, not in Metecho. +When the Task has been added to the Project on Github, the Task status will update to Complete. + +*** +Step 13 - Create an Epic/s +Epic - Major contributions to a Project that include more than one related Task. Epics are more than containers for multiple Tasks. Like Tasks, creating an Epic creates a branch in GitHub. Tasks that are part of an Epic create branches from the Epic branch in GitHub. + +Select the Epics tab. +Create a new Epic of your own (or from an existing GitHub Issue). +Name the Epic. +The name can be a brief description of the work. +Select create a branch on GitHub unless you know the name of a specific branch you would like to use. +Use the optional description section for more detail, if needed. +Select Create to save and navigate to your Epic detail view. +If you need to edit the Epic name or description, or delete the Epic, select the gear icon in the top right corner. Deleting an Epic deletes all Tasks and Orgs as well. +Step 14 - Add Collaborators +Select Add or Remove Collaborators. +Select one or more Collaborators to do the work on the Tasks in this Epic. +If you do not see the people you want to invite, contact an admin for the repository on GitHub and ensure that the people are collaborators. Then re-sync GitHub collaborators in Metecho. +If you need to remove a collaborator, select the X icon in the Collaborator card or uncheck the box in the list of Collaborators. + +(To continue, go up to Step 2 - Create a Task/s.) + +*** +Create a Project +In the Project list view, select Create Project. +If you do not see the GitHub Organization you want to work in: +Confirm that you are logged into the correct Metecho account. +Contact an admin for the repository on GitHub and ensure that you are a collaborator. +Select Re-sync GitHub Organizations. +Select a GitHub Organization. +Create a Project name. +Select people to add as Collaborators on the Project. +If you do not see the people you want to invite, contact an admin for the repository on GitHub and ensure that the people are collaborators. Then re-sync GitHub collaborators in Metecho. +Review your Project selections. Go Back to make edits, Cancel, or Create Project. + +(To continue, go up to Step 2 - Create a Task/s or Step 13 - Create an Epic/s.) + +*** +Additional Help +Select the ? menu in the top right corner of Metecho at any time to: +View specific walkthroughs. +Activate self-guided tour mode for more detail about everything Metecho can do for you. From c3e9d30f22ec2c0868d972e1f4ecc0ef85c36942 Mon Sep 17 00:00:00 2001 From: Sondra Date: Mon, 13 Jun 2022 15:02:55 -0600 Subject: [PATCH 14/62] Create metecho-how-to.md Metecho how to with markdown --- docs/metecho-how-to.md | 150 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 docs/metecho-how-to.md diff --git a/docs/metecho-how-to.md b/docs/metecho-how-to.md new file mode 100644 index 000000000..6e0022c63 --- /dev/null +++ b/docs/metecho-how-to.md @@ -0,0 +1,150 @@ +# Steps to Guide a Team Through Metecho + +## Step 0 - Log in with GitHub +- Create a GitHub account, if you don’t yet have one. +- Contact an admin for the repository (e.g. Nonprofit Success Pack) on GitHub and ensure that you and anyone you’d like to work with are collaborators. + +If you want to create a project, skip down to [Create a Project](#create-a-project). + + +## Step 1 - Select a Project +**Project** - *(e.g. Nonprofit Success Pack) Projects contain all the work being done. They are equivalent to GitHub repositories.* + +- Select the Project you want to contribute to. +- If you do not see the Project you want to work on: + - Confirm that you are logged into the correct Metecho account. + - Contact an admin for the repository on GitHub and ensure that you are a collaborator. + - Select Re-sync Projects in Metecho. + +To continue, go to **Step 2 - Create a Task/s** or, if you have a set of several closely related Tasks in mind, skip to [Step 13 - Create an Epic/s](#step-13---create-an-epics) + +## Step 2 - Create a Task/s +**Task** - *Tasks represent small changes to the Project, and may stand alone or be part of an Epic. Creating a Task creates a branch in GitHub.* + +- Select the Tasks tab. +- Create a new Task of your own (or from an existing GitHub Issue). + - Name the Task. +- The name can be a brief description of the work. +- Use the optional description section for more detail, if needed. +- Use the recommended dev org type unless you know of a specific reason to use a different one. +- Select Create to save and navigate to your Task detail view. Select Create & New to continue creating multiple Tasks that are unrelated to each other. +- If you need to edit the Task name or description, or delete the Task, select the gear icon in the top right corner. Deleting a Task deletes all the Orgs as well. + +## Step 3 - Invite Task Developer/s +**Developer** - *The person invited to do the work of a Task.* + +- Assign yourself or invite another person to be the Developer for each Task you created. +- Invited Developers will see an alert in Metecho and receive an email invitation. They need to accept the invitation if they want to begin development on the Task. +- If you do not see the person you want to invite, contact an admin for the repository on GitHub and ensure that the person is a collaborator. Then re-sync GitHub collaborators in Metecho. +- If you need to change or remove the Task Developer, use the drop down menu on the Developer card in the Task detail view. + +## Step 4 - Create Dev Org +**Dev Org** - *A temporary Salesforce org where a Developer can work on contributions to a Project. Dev Orgs expire after 30 days, and all unretrieved work is deleted.* + +- Review the Next Steps for This Task list to see progress and who is responsible for the next step. +- To begin work, the Developer will need to select Create Org in the Dev Org card. +- Dev Org creation can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the Dev Org is ready. + +## Step 5 - Make Changes in Dev Org +- **This step takes place in the new Salesforce Dev Org, not in Metecho.** +- Select View Org on the Dev Org card to navigate out of Metecho and make your changes in the temporary Salesforce Dev Org. + +## Step 6 - Retrieve Changes from Dev Org +**Retrieve Changes** - *Pull the work you did in your Salesforce Dev Org into Metecho so that other people can review it. Developers may retrieve changes as many times as they like while they are working.* + +- When the Developer is ready to pull the Salesforce Dev Org work into Metecho, they need to select Check for Unretrieved Changes (button located just above the Developer card in the Task detail view). +- Select the location to retrieve changes. + - Use the preselected Package Directory unless you know of a specific reason to select a different option. +- Select the changes to retrieve (or ignore). +- Create a commit message that briefly describes the changes. +- Select Retrieve Selected Changes. +- Retrieving changes can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the changes have been retrieved. +- Note that the Developer, commit message, and date now appear in a Commit History list in the Task detail view. + +## Step 7 - Submit Task Changes for Testing +**Submit Changes** - *Document all the changes a Developer made in a Salesforce Dev Org so that a Tester can test the work and leave a review. This action creates a pull request in GitHub.* + +**Pull Request** - *A way to propose changes on GitHub so that the maintainers of a Project can review them and accept the changes or request revisions.* + +- When the Developer is finished working and retrieving changes, they need to select Submit Task for Testing (button located just above the Developer card in the Task detail view). +- Each commit message briefly described what changed. Now, when submitting the Task for testing, describe all the critical changes and why they were made so the Tester will understand how to test them. +- Select Submit Task for Testing. + +## Step 8 - Invite a Tester +**Tester** - *The person who will look at the Developer’s work, and then approve the work or request changes that must be addressed before the Task can be completed.* + +- Assign yourself or invite another person to be the Tester for each Task you created. +- Testers can be invited at any time and, just like Developers, they need to accept the invitation in order to begin testing. +- If you do not see the person you want to invite, contact an admin for the repository on GitHub and ensure that the person is a collaborator. Then re-sync GitHub collaborators in Metecho. +- If you need to change or remove the Task Tester, use the drop down menu on the Tester card in the Task detail view. + +## Step 9 - Create Test Org +**Test Org** - *A temporary Salesforce org where the Tester can look over the Developer’s work on a specific Task. Test Orgs expire after 30 days.* + +- Remember, you can review the Next Steps for This Task list to see progress and who is responsible for the next step. +- To begin testing, a Task Tester will need to select Create Org in the Test Org card. +- Dev Org creation can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the Dev Org is ready. + +## Step 10 - Test Changes in Test Org +- **This step takes place in the new Salesforce Test Org, not in Metecho.** +- Select View Org on the Test Org card to navigate out of Metecho and test the Developer’s changes in the temporary Salesforce Test Org. + +## Step 11 - Submit a Review +- When the Tester is finished testing the Developer’s changes in the Test Org, select Submit Review on the Test Org card. +- Select Approve if no more work is needed. +- Select Request Changes if the Developer needs to make revisions. +- Leave a description, especially if there are still changes the Developer needs to make, so that the Developer understands what to do next. +- Leaving Delete Test Org checked makes sense in most cases. + - If the changes are Approved, there is no longer any need for the Test Org. + - If the Developer needs to make changes, the Tester will need to create a new Test Org to see the newly retrieved changes. +- Select Submit Review. + - If any change needs to be made to the review, select Update Review in the Test Org card. + +## Step 12 - Merge Pull Request on GitHub +**Merge** - *To add proposed changes to the Project on GitHub.* + +- **This step takes place on GitHub, not in Metecho.** +- When the Task has been added to the Project on Github, the Task status will update to Complete. + +*** + +## Step 13 - Create an Epic/s +**Epic** - *Major contributions to a Project that include more than one related Task. Epics are more than containers for multiple Tasks. Like Tasks, creating an Epic creates a branch in GitHub. Tasks that are part of an Epic create branches from the Epic branch in GitHub.* + +- Select the Epics tab. +- Create a new Epic of your own (or from an existing GitHub Issue). +- Name the Epic. + - The name can be a brief description of the work. +- Select create a branch on GitHub unless you know the name of a specific branch you would like to use. +- Use the optional description section for more detail, if needed. +- Select Create to save and navigate to your Epic detail view. +- If you need to edit the Epic name or description, or delete the Epic, select the gear icon in the top right corner. Deleting an Epic deletes all Tasks and Orgs as well. + +## Step 14 - Add Collaborators +- Select Add or Remove Collaborators. +- Select one or more Collaborators to do the work on the Tasks in this Epic. +- If you do not see the people you want to invite, contact an admin for the repository on GitHub and ensure that the people are collaborators. Then re-sync GitHub collaborators in Metecho. +- If you need to remove a collaborator, select the X icon in the Collaborator card or uncheck the box in the list of Collaborators. + +To continue, go up to [Step 2 - Create a Task/s](#step-2---create-a-tasks) + +*** +## Create a Project +- In the Project list view, select Create Project. +- If you do not see the GitHub Organization you want to work in: + - Confirm that you are logged into the correct Metecho account. + - Contact an admin for the repository on GitHub and ensure that you are a collaborator. + - Select Re-sync GitHub Organizations. +- Select a GitHub Organization. +- Create a Project name. +- Select people to add as Collaborators on the Project. +- If you do not see the people you want to invite, contact an admin for the repository on GitHub and ensure that the people are collaborators. Then re-sync GitHub collaborators in Metecho. +- Review your Project selections. Go Back to make edits, Cancel, or Create Project. + +To continue, go up to [Step 2 - Create a Task/s](#step-2---create-a-tasks) or [Step 13 - Create an Epic/s](#step-13---create-an-epics) + +*** +## Additional Help +**Select the ? menu** in the top right corner of Metecho at any time to: +- View specific walkthroughs. +- Activate self-guided tour mode for more detail about everything Metecho can do for you. From c4675899960728bf092ff9c40ca654ff1ba2f01a Mon Sep 17 00:00:00 2001 From: Sondra Date: Mon, 13 Jun 2022 15:04:14 -0600 Subject: [PATCH 15/62] Delete metecho-how-to --- docs/metecho-how-to | 135 -------------------------------------------- 1 file changed, 135 deletions(-) delete mode 100644 docs/metecho-how-to diff --git a/docs/metecho-how-to b/docs/metecho-how-to deleted file mode 100644 index 0b3523584..000000000 --- a/docs/metecho-how-to +++ /dev/null @@ -1,135 +0,0 @@ -# Steps to Guide a Team Through Metecho - -Step 0 - Log in with GitHub -Create a GitHub account, if you don’t yet have one. -Contact an admin for the repository (e.g. Nonprofit Success Pack) on GitHub and ensure that you and anyone you’d like to work with are collaborators. - -(If you want to create a project, skip down to Create a Project.) -Step 1 - Select a Project -Project - (e.g. Nonprofit Success Pack) Projects contain all the work being done. They are equivalent to GitHub repositories. - -Select the Project you want to contribute to. -If you do not see the Project you want to work on: -Confirm that you are logged into the correct Metecho account. -Contact an admin for the repository on GitHub and ensure that you are a collaborator. -Select Re-sync Projects in Metecho. - -(To continue, go to Step 2 - Create a Task/s or, if you have a set of several closely related Tasks in mind, skip to Step 13 - Create an Epic.) - -Step 2 - Create a Task/s -Task - Tasks represent small changes to the Project, and may stand alone or be part of an Epic. Creating a Task creates a branch in GitHub. - -Select the Tasks tab. -Create a new Task of your own (or from an existing GitHub Issue). -Name the Task. -The name can be a brief description of the work. -Use the optional description section for more detail, if needed. -Use the recommended dev org type unless you know of a specific reason to use a different one. -Select Create to save and navigate to your Task detail view. Select Create & New to continue creating multiple Tasks that are unrelated to each other. -If you need to edit the Task name or description, or delete the Task, select the gear icon in the top right corner. Deleting a Task deletes all the Orgs as well. -Step 3 - Invite Task Developer/s -Developer - The person invited to do the work of a Task. - -Assign yourself or invite another person to be the Developer for each Task you created. -Invited Developers will see an alert in Metecho and receive an email invitation. They need to accept the invitation if they want to begin development on the Task. -If you do not see the person you want to invite, contact an admin for the repository on GitHub and ensure that the person is a collaborator. Then re-sync GitHub collaborators in Metecho. -If you need to change or remove the Task Developer, use the drop down menu on the Developer card in the Task detail view. -Step 4 - Create Dev Org -Dev Org - A temporary Salesforce org where a Developer can work on contributions to a Project. Dev Orgs expire after 30 days, and all unretrieved work is deleted. - -Review the Next Steps for This Task list to see progress and who is responsible for the next step. -To begin work, the Developer will need to select Create Org in the Dev Org card. -Dev Org creation can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the Dev Org is ready. -Step 5 - Make Changes in Dev Org -This step takes place in the new Salesforce Dev Org, not in Metecho. -Select View Org on the Dev Org card to navigate out of Metecho and make your changes in the temporary Salesforce Dev Org. -Step 6 - Retrieve Changes from Dev Org -Retrieve Changes - Pull the work you did in your Salesforce Dev Org into Metecho so that other people can review it. Developers may retrieve changes as many times as they like while they are working. - -When the Developer is ready to pull the Salesforce Dev Org work into Metecho, they need to select Check for Unretrieved Changes (button located just above the Developer card in the Task detail view). -Select the location to retrieve changes. -Use the preselected Package Directory unless you know of a specific reason to select a different option. -Select the changes to retrieve (or ignore). -Create a commit message that briefly describes the changes. -Select Retrieve Selected Changes. -Retrieving changes can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the changes have been retrieved. -Note that the Developer, commit message, and date now appear in a Commit History list in the Task detail view. -Step 7 - Submit Task Changes for Testing -Submit Changes - Document all the changes a Developer made in a Salesforce Dev Org so that a Tester can test the work and leave a review. This action creates a pull request in GitHub. -Pull Request - A way to propose changes on GitHub so that the maintainers of a Project can review them and accept the changes or request revisions. - -When the Developer is finished working and retrieving changes, they need to select Submit Task for Testing (button located just above the Developer card in the Task detail view). -Each commit message briefly described what changed. Now, when submitting the Task for testing, describe all the critical changes and why they were made so the Tester will understand how to test them. -Select Submit Task for Testing. -Step 8 - Invite a Tester -Tester - The person who will look at the Developer’s work, and then approve the work or request changes that must be addressed before the Task can be completed. - -Assign yourself or invite another person to be the Tester for each Task you created. -Testers can be invited at any time and, just like Developers, they need to accept the invitation in order to begin testing. -If you do not see the person you want to invite, contact an admin for the repository on GitHub and ensure that the person is a collaborator. Then re-sync GitHub collaborators in Metecho. -If you need to change or remove the Task Tester, use the drop down menu on the Tester card in the Task detail view. -Step 9 - Create Test Org -Test Org - A temporary Salesforce org where the Tester can look over the Developer’s work on a specific Task. Test Orgs expire after 30 days. - -Remember, you can review the Next Steps for This Task list to see progress and who is responsible for the next step. -To begin testing, a Task Tester will need to select Create Org in the Test Org card. -Dev Org creation can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the Dev Org is ready. -Step 10 - Test Changes in Test Org -This step takes place in the new Salesforce Test Org, not in Metecho. -Select View Org on the Test Org card to navigate out of Metecho and test the Developer’s changes in the temporary Salesforce Test Org. -Step 11 - Submit a Review -When the Tester is finished testing the Developer’s changes in the Test Org, select Submit Review on the Test Org card. -Select Approve if no more work is needed. -Select Request Changes if the Developer needs to make revisions. -Leave a description, especially if there are still changes the Developer needs to make, so that the Developer understands what to do next. -Leaving Delete Test Org checked makes sense in most cases. -If the changes are Approved, there is no longer any need for the Test Org. -If the Developer needs to make changes, the Tester will need to create a new Test Org to see the newly retrieved changes. -Select Submit Review. -If any change needs to be made to the review, select Update Review in the Test Org card. -Step 12 - Merge Pull Request on GitHub -Merge - To add proposed changes to the Project on GitHub. - -This step takes place on GitHub, not in Metecho. -When the Task has been added to the Project on Github, the Task status will update to Complete. - -*** -Step 13 - Create an Epic/s -Epic - Major contributions to a Project that include more than one related Task. Epics are more than containers for multiple Tasks. Like Tasks, creating an Epic creates a branch in GitHub. Tasks that are part of an Epic create branches from the Epic branch in GitHub. - -Select the Epics tab. -Create a new Epic of your own (or from an existing GitHub Issue). -Name the Epic. -The name can be a brief description of the work. -Select create a branch on GitHub unless you know the name of a specific branch you would like to use. -Use the optional description section for more detail, if needed. -Select Create to save and navigate to your Epic detail view. -If you need to edit the Epic name or description, or delete the Epic, select the gear icon in the top right corner. Deleting an Epic deletes all Tasks and Orgs as well. -Step 14 - Add Collaborators -Select Add or Remove Collaborators. -Select one or more Collaborators to do the work on the Tasks in this Epic. -If you do not see the people you want to invite, contact an admin for the repository on GitHub and ensure that the people are collaborators. Then re-sync GitHub collaborators in Metecho. -If you need to remove a collaborator, select the X icon in the Collaborator card or uncheck the box in the list of Collaborators. - -(To continue, go up to Step 2 - Create a Task/s.) - -*** -Create a Project -In the Project list view, select Create Project. -If you do not see the GitHub Organization you want to work in: -Confirm that you are logged into the correct Metecho account. -Contact an admin for the repository on GitHub and ensure that you are a collaborator. -Select Re-sync GitHub Organizations. -Select a GitHub Organization. -Create a Project name. -Select people to add as Collaborators on the Project. -If you do not see the people you want to invite, contact an admin for the repository on GitHub and ensure that the people are collaborators. Then re-sync GitHub collaborators in Metecho. -Review your Project selections. Go Back to make edits, Cancel, or Create Project. - -(To continue, go up to Step 2 - Create a Task/s or Step 13 - Create an Epic/s.) - -*** -Additional Help -Select the ? menu in the top right corner of Metecho at any time to: -View specific walkthroughs. -Activate self-guided tour mode for more detail about everything Metecho can do for you. From bee068abcd35e2cbcb8e34a35a2221a55ec93c59 Mon Sep 17 00:00:00 2001 From: Ed Rivas Date: Tue, 14 Jun 2022 01:01:07 +0000 Subject: [PATCH 16/62] Un-escape quotes --- CONTRIBUTING.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 223a0e41d..2c9ccc292 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ ## Docker-based development 1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop) and - make sure it is running. Ensure you\'re running `docker-compose` at least + make sure it is running. Ensure you're running `docker-compose` at least version `1.25.2` to avoid container-abort bugs. The latest Docker Desktop should come with this version or later. @@ -57,7 +57,7 @@ 5. Visit in your browser. -6. When you\'re done working on Metecho, `Ctrl-C` in the terminal where the +6. When you're done working on Metecho, `Ctrl-C` in the terminal where the containers are running to exit. You can also `./derrick down` to stop all running containers, or `./derrick prune` to clean up unused images/containers. (`docker-compose ps` will tell you what containers are @@ -97,19 +97,19 @@ enable these additional permissions: - Organization permissions - Members: Read & write -To enable logging in with GitHub, set the \"User authorization callback URL\" to +To enable logging in with GitHub, set the "User authorization callback URL" to `https:///accounts/github/login/callback/`, and be sure the -\"Request user authorization (OAuth) during installation\" box is checked. +"Request user authorization (OAuth) during installation" box is checked. -To enable GitHub webhooks, set the \"Webhook URL\" to -`https:///api/hook/`, and be sure the \"Active\" box is -checked and \"SSL verification\" is enabled. +To enable GitHub webhooks, set the "Webhook URL" to +`https:///api/hook/`, and be sure the "Active" box is checked +and "SSL verification" is enabled. -Use the \"Webhook secret\" value as your `GITHUB_HOOK_SECRET` environment -variable in Metecho. +Use the "Webhook secret" value as your `GITHUB_HOOK_SECRET` environment variable +in Metecho. -Use the app\'s \"App ID\" as `GITHUB_APP_ID`, \"Client ID\" as -`GITHUB_CLIENT_ID`, and \"Client secret\" as `GITHUB_CLIENT_SECRET`. +Use the app's "App ID" as `GITHUB_APP_ID`, "Client ID" as `GITHUB_CLIENT_ID`, +and "Client secret" as `GITHUB_CLIENT_SECRET`. Finally, generate a new private key for the app, replace newlines with `\n`, and set it as the `DOCKER_GITHUB_APP_KEY` environment variable (the entire key, not @@ -139,8 +139,8 @@ to your computer. Run it like so: You will get output that indicates the name of the ngrok tunnel, which will look like `https://.ngrok.io`. You will need to adjust the GitHub App to point to the `/api/hook/` path of your ngrok tunnel (e.g. -`https://.ngrok.io/api/hook/`). This means that it\'s a -one-person-at-a-time thing, which is a problem for which we don\'t yet have a +`https://.ngrok.io/api/hook/`). This means that it's a +one-person-at-a-time thing, which is a problem for which we don't yet have a solution. ## Setting up the database @@ -154,11 +154,11 @@ To populate the database with sample data for development, run: $ ./derrick truncate $ ./derrick populate -To allow automated emails to send with correct links, you\'ll need to set up the -default `Site` object in the Django admin. Assuming you\'ve already set your -user up as a superuser, go to -and set the \"Domain name\" field appropriately (to `localhost:8080`). If you -are setting up a deployed production or staging instance, set this value to the +To allow automated emails to send with correct links, you'll need to set up the +default `Site` object in the Django admin. Assuming you've already set your user +up as a superuser, go to and +set the "Domain name" field appropriately (to `localhost:8080`). If you are +setting up a deployed production or staging instance, set this value to the domain from which you are serving that instance. ## Docker development tasks @@ -190,7 +190,7 @@ run them inside the Docker image. This takes the general form `docker-compose run --no-deps web [command]`. In some cases, such as for migrations or a Django shell, you will want to omit the `--no-deps` flag. -You shouldn\'t need to run any other setup tasks; the Docker images will take +You shouldn't need to run any other setup tasks; the Docker images will take care of setting up a database and installing Python and JS dependencies for you. When you change Python or JS dependencies, you will need to rebuild the Docker @@ -212,8 +212,8 @@ extension pack. Once you have the extension pack installed, when you open the Metecho folder in VS Code, you will be prompted to `Reopen in Container`. Doing so will effectively run `docker-compose up` and reload your window, now running inside -the Docker container. If you do not see the prompt, run the \"Remote-Containers: -Open Folder in Container\...\" command from the VS Code Command Palette to start +the Docker container. If you do not see the prompt, run the "Remote-Containers: +Open Folder in Container\..." command from the VS Code Command Palette to start the Docker container. A number of project-specific VS Code extensions will be automatically installed @@ -264,7 +264,7 @@ build. When this file changes, translations must be copied over to the `locales/en/translation.json` file in order to have any effect. Strings with dynamic content (i.e. known only at runtime) cannot be -automatically parsed, but will log errors while the app is running if they\'re +automatically parsed, but will log errors while the app is running if they're missing from the served translation files. To resolve, add the missing key:value translations to `locales//translation.json`. From 626afb620e8b712d6c857d184865a43000734dc0 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Tue, 14 Jun 2022 13:49:47 +0200 Subject: [PATCH 17/62] draft component library contributing docs --- docs/component-library-how-to.md | 91 ++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 docs/component-library-how-to.md diff --git a/docs/component-library-how-to.md b/docs/component-library-how-to.md new file mode 100644 index 000000000..2865eb82c --- /dev/null +++ b/docs/component-library-how-to.md @@ -0,0 +1,91 @@ +# Contributing to the Metecho Component Library + +The Metecho component library is a source for developers and non-developers +alike to get a quick overview of how components that make up the project behave +and appear. + +Components used in in the project are custom versions of SLDS components. + +The library was created with Storybook and is deployed using +[Storybook Deployer](https://github.com/storybookjs/storybook-deployer). + +## Component Library Structure + +Components for the library live in `src/stories/` in folders organized similarly +to how the original component is organized in the `src/js/components` directory. +For example, the component library version of the modal for creating a new +**Epic**, the `createForm` component, would be found in the `epics/` directory: + +``` +src/ + stories/ + epics/ + createForm/ + index.stories.mdx + index.stories.tsx +``` + +Each component folder consists of two files. The `.mdx` file is where +documentation for each component is stored. The rendering of the component, with +all of its relevant states, is located in the `.tsx` file. + +## Rendering Components + +To render a component, follow the the general +[Storybook steps](https://storybook.js.org/docs/react/writing-stories/introduction) +for configuring a story. + +If a component needs to be wrapped in a +[decorator](https://storybook.js.org/docs/react/writing-stories/decorators), +first, import the mock Redux store: + +``` +import { withRedux } from '../decorators'; + +``` + +and add a `decorators` prop to the default export: + +``` +export default { + title: 'Commits/List/Example', + component: CommitListComponent, + decorators: [withRedux()], +}; + +``` + +## Sample Data + +Some components require sample data to function correctly. These, and other +required API url routes, can be found in the `fixtures.ts` file in the +`/stories` directory. + +Storybook defaults to showing each component prop as a control for each +component in the library. For this project, props that less relevant to the +various states of the component have been disabled. + +## Documenting Components + +Documentation for each component is written in a separate `.mdx` file. This +should at minimum consist of the following: + +- A header that shows the name of the component and a brief description of its + role +- A general overview of the component explaining its purpose and possible states +- An embedded rendering of the component + +Metecho-specific terms are capitalized and bolded. References to component props +and states are written as `code`. + +## Deploying to Github Pages + +Through [Storybook Deployer](https://github.com/storybookjs/storybook-deployer), +the library is set to deploy automatically to Github Pages each time a new +commit is made to the main branch. + +The workflow for this job is located in `.github/workflows/deploy-storybook.yml` + +Additional core Storybook configuration settings (i.e. global decorators and +parameters, webpack configuration, story loading, etc.) can be found in the +`.storybook` directory. From 04654256e7e9781500d70629d4f314f5bc738e4a Mon Sep 17 00:00:00 2001 From: dvdherron Date: Tue, 14 Jun 2022 15:29:00 +0200 Subject: [PATCH 18/62] flesh out details --- CONTRIBUTING.md | 3 ++ docs/component-library-how-to.md | 86 ++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c9ccc292..c7bdaa1d9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -283,3 +283,6 @@ two commands: After running one of these commands, you can view the Storybook at in your browser. + +For more detailed steps on contributing to the component library, see +`docs/component-library-how-to.md`. diff --git a/docs/component-library-how-to.md b/docs/component-library-how-to.md index 2865eb82c..01b68022f 100644 --- a/docs/component-library-how-to.md +++ b/docs/component-library-how-to.md @@ -4,26 +4,28 @@ The Metecho component library is a source for developers and non-developers alike to get a quick overview of how components that make up the project behave and appear. -Components used in in the project are custom versions of SLDS components. +Components used in in the project are custom versions of +[SLDS components](https://react.lightningdesignsystem.com/). -The library was created with Storybook and is deployed using +The library was created with [Storybook](https://storybook.js.org/) +and is deployed using [Storybook Deployer](https://github.com/storybookjs/storybook-deployer). ## Component Library Structure -Components for the library live in `src/stories/` in folders organized similarly -to how the original component is organized in the `src/js/components` directory. +Components for the library are located in `src/stories/` in folders organized +similarly to how the original components are organized in `src/js/components`. For example, the component library version of the modal for creating a new **Epic**, the `createForm` component, would be found in the `epics/` directory: -``` -src/ - stories/ - epics/ - createForm/ - index.stories.mdx - index.stories.tsx -``` + + src/ + stories/ + epics/ + createForm/ + index.stories.mdx + index.stories.tsx + Each component folder consists of two files. The `.mdx` file is where documentation for each component is stored. The rendering of the component, with @@ -35,35 +37,57 @@ To render a component, follow the the general [Storybook steps](https://storybook.js.org/docs/react/writing-stories/introduction) for configuring a story. +In general, this consists of: + +- Importing the component from `src/js/components` +- Setting where and how Storybook lists the component with a +[default export](https://storybook.js.org/docs/react/writing-stories/introduction#default-export) +- [Creating a template](https://storybook.js.org/docs/react/writing-stories/introduction#default-export) for how `args` map to rendering +- Setting the component `args` and `argTypes` +- Naming the component story by setting a `storyName` + +## Run Component Library Locally + +To view changes while you work on the library, use one of the below commands: + + $ ./derrick storybook # if running outside of container + $ yarn storybook # if working in a remote container in VS Code + +After running one of these commands, you can view the Storybook at + in your browser. + +# Decorators + If a component needs to be wrapped in a [decorator](https://storybook.js.org/docs/react/writing-stories/decorators), -first, import the mock Redux store: +first import the mock Redux store: + + + import { withRedux } from '../decorators'; + + -``` -import { withRedux } from '../decorators'; +and then add a `decorators` prop to the default export: -``` -and add a `decorators` prop to the default export: + export default { + title: 'Commits/List/Example', + component: CommitListComponent, + decorators: [withRedux()], + }; -``` -export default { - title: 'Commits/List/Example', - component: CommitListComponent, - decorators: [withRedux()], -}; -``` ## Sample Data -Some components require sample data to function correctly. These, and other -required API url routes, can be found in the `fixtures.ts` file in the -`/stories` directory. +Some components require sample data and props to function correctly. This data, +and other required API url routes, can be found in `stories/fixtures.ts`. Storybook defaults to showing each component prop as a control for each -component in the library. For this project, props that less relevant to the -various states of the component have been disabled. +component in the library. For this project, props that are less relevant to the +various states of the component have been disabled. Props more relevant to state +and display are set with appropriate +[control types](https://storybook.js.org/docs/react/essentials/controls#choosing-the-control-type. ## Documenting Components @@ -81,8 +105,8 @@ and states are written as `code`. ## Deploying to Github Pages Through [Storybook Deployer](https://github.com/storybookjs/storybook-deployer), -the library is set to deploy automatically to Github Pages each time a new -commit is made to the main branch. +the library is set to deploy automatically as a static site to Github Pages each +time a commit is made to the main branch. The workflow for this job is located in `.github/workflows/deploy-storybook.yml` From 979544ec1aab6f096e79e9e527595b38828e4440 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Tue, 14 Jun 2022 15:42:37 +0200 Subject: [PATCH 19/62] Frontend code review edits --- src/js/components/utils/deleteModal.tsx | 2 +- src/js/store/actions.ts | 27 ++++++++++++------- src/js/utils/api.ts | 16 ----------- test/js/components/utils/deleteModal.test.jsx | 2 +- test/js/store/actions.test.js | 2 +- test/js/utils/api.test.js | 27 ------------------- 6 files changed, 20 insertions(+), 56 deletions(-) diff --git a/src/js/components/utils/deleteModal.tsx b/src/js/components/utils/deleteModal.tsx index c544c3ce2..81b55877e 100644 --- a/src/js/components/utils/deleteModal.tsx +++ b/src/js/components/utils/deleteModal.tsx @@ -48,7 +48,7 @@ const DeleteModal = ({ deleteObject({ objectType: modelType, object: model, - userDeleteUrl: getModelDeleteUrl(modelType), + url: getModelDeleteUrl(modelType), }), ) .then(() => { diff --git a/src/js/store/actions.ts b/src/js/store/actions.ts index b8ee87f28..b9ea40805 100644 --- a/src/js/store/actions.ts +++ b/src/js/store/actions.ts @@ -1,7 +1,7 @@ import { ThunkResult } from '@/js/store'; import { Epic } from '@/js/store/epics/reducer'; import { Task } from '@/js/store/tasks/reducer'; -import apiFetch, { addUrlParams, getDeleteObjectUrl } from '@/js/utils/api'; +import apiFetch, { addUrlParams } from '@/js/utils/api'; import { ObjectTypes } from '@/js/utils/constants'; interface CreateObjectPayload { @@ -293,27 +293,34 @@ export const createObject = export const deleteObject = ({ objectType, + url, object, shouldSubscribeToObject = false, - userDeleteUrl, }: { objectType: ObjectTypes; + url?: string; object: { id: string; [key: string]: any }; shouldSubscribeToObject?: boolean | ((obj: any) => boolean); - userDeleteUrl?: string | undefined; }): ThunkResult> => async (dispatch) => { - const baseUrl = getDeleteObjectUrl(objectType, object.id, userDeleteUrl); + if (!url) { + const urlFn = window.api_urls[`${objectType}_detail`]; + if (urlFn && object.id) { + // eslint-disable-next-line no-param-reassign + url = urlFn(object.id); + } + } + dispatch({ type: 'DELETE_OBJECT_STARTED', - payload: { objectType, url: baseUrl, object }, + payload: { objectType, url, object }, }); try { - if (!baseUrl) { + if (!url) { throw new Error(`No URL found for object: ${objectType}`); } await apiFetch({ - url: baseUrl, + url, dispatch, opts: { method: 'DELETE' }, }); @@ -331,17 +338,17 @@ export const deleteObject = if (objectType === 'user') { return dispatch({ type: 'USER_LOGGED_OUT' as const, - payload: { objectType, url: baseUrl, object }, + payload: { objectType, url, object }, }); } return dispatch({ type: 'DELETE_OBJECT_SUCCEEDED' as const, - payload: { objectType, url: baseUrl, object }, + payload: { objectType, url, object }, }); } catch (err) { dispatch({ type: 'DELETE_OBJECT_FAILED', - payload: { objectType, url: baseUrl, object }, + payload: { objectType, url, object }, }); throw err; } diff --git a/src/js/utils/api.ts b/src/js/utils/api.ts index e2ae2af3c..453739c7a 100644 --- a/src/js/utils/api.ts +++ b/src/js/utils/api.ts @@ -125,20 +125,4 @@ export const removeUrlParam = (key: string, search?: string) => { return params.toString(); }; -export const getDeleteObjectUrl = ( - objectType: ObjectTypes, - id: string, - userDeleteUrl: string | undefined, -) => { - if (userDeleteUrl) { - return userDeleteUrl; - } - const urlFn = window.api_urls[`${objectType}_detail`]; - let baseUrl; - if (urlFn && id) { - baseUrl = urlFn(id); - } - return baseUrl; -}; - export default apiFetch; diff --git a/test/js/components/utils/deleteModal.test.jsx b/test/js/components/utils/deleteModal.test.jsx index 429165ce0..fe0754c9c 100644 --- a/test/js/components/utils/deleteModal.test.jsx +++ b/test/js/components/utils/deleteModal.test.jsx @@ -80,7 +80,7 @@ describe('', () => { expect(deleteObject).toHaveBeenCalledWith({ objectType: 'user', object: defaultUser, - userDeleteUrl: '/api/user/', + url: '/api/user/', }); expect(context.action).toBe('PUSH'); expect(context.url).toBe('/login'); diff --git a/test/js/store/actions.test.js b/test/js/store/actions.test.js index 631abac4e..ab2f864d6 100644 --- a/test/js/store/actions.test.js +++ b/test/js/store/actions.test.js @@ -628,7 +628,7 @@ describe('deleteObject', () => { actions.deleteObject({ objectType: 'user', object: { id: '123' }, - userDeleteUrl: userUrl, + url: userUrl, }), ) .then(() => { diff --git a/test/js/utils/api.test.js b/test/js/utils/api.test.js index f5cad0b73..11f5f6e9d 100644 --- a/test/js/utils/api.test.js +++ b/test/js/utils/api.test.js @@ -3,7 +3,6 @@ import fetchMock from 'fetch-mock'; import { addError } from '@/js/store/errors/actions'; import apiFetch, { addUrlParams, - getDeleteObjectUrl, getUrlParam, removeUrlParam, } from '@/js/utils/api'; @@ -182,30 +181,4 @@ describe('removeUrlParam', () => { return expect(actual).toBe(expected); }); - - describe('getDeleteObjectUrl', () => { - test('returns correct url for user object type', () => { - const expected = '/api/user/'; - - const actual = getDeleteObjectUrl('user', '123', '/api/user/'); - - return expect(actual).toBe(expected); - }); - - test('returns correct url for task object type', () => { - const expected = '/api/tasks/123/'; - - const actual = getDeleteObjectUrl('task', '123'); - - return expect(actual).toBe(expected); - }); - - test('returns correct url for epic object type', () => { - const expected = '/api/epics/123/'; - - const actual = getDeleteObjectUrl('epic', '123'); - - return expect(actual).toBe(expected); - }); - }); }); From a117bbb30132aac9e70bca38bca87f291222d953 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Tue, 14 Jun 2022 10:17:18 -0400 Subject: [PATCH 20/62] try different dropdown arrangement --- src/js/components/user/info.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/js/components/user/info.tsx b/src/js/components/user/info.tsx index d252f5493..087849f87 100644 --- a/src/js/components/user/info.tsx +++ b/src/js/components/user/info.tsx @@ -287,9 +287,8 @@ const UserDropdown = () => { {user.username}
- + |
-
From 1aef642cac57611aa417dcabefcf61e70ecf1603 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Tue, 14 Jun 2022 10:37:23 -0400 Subject: [PATCH 21/62] review --- .heroku/release.sh | 2 +- docs/metecho-how-to.md | 227 ++++++++++++++++--------- test/js/store/projects/actions.test.js | 10 +- 3 files changed, 153 insertions(+), 86 deletions(-) diff --git a/.heroku/release.sh b/.heroku/release.sh index f1203822b..bc3096db5 100755 --- a/.heroku/release.sh +++ b/.heroku/release.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env bash set -e if [ -n "$CTC_URL" ] ; then diff --git a/docs/metecho-how-to.md b/docs/metecho-how-to.md index 6e0022c63..eac7a5ce2 100644 --- a/docs/metecho-how-to.md +++ b/docs/metecho-how-to.md @@ -1,150 +1,217 @@ # Steps to Guide a Team Through Metecho -## Step 0 - Log in with GitHub -- Create a GitHub account, if you don’t yet have one. -- Contact an admin for the repository (e.g. Nonprofit Success Pack) on GitHub and ensure that you and anyone you’d like to work with are collaborators. - -If you want to create a project, skip down to [Create a Project](#create-a-project). +## Step 0 - Log In with GitHub +- Create a [GitHub](https://github.com) account, if you don’t yet have one. +- Contact an admin for the GitHub repository you want to contribute to (e.g. + Nonprofit Success Pack) on GitHub and ensure that you and anyone you’d like to + work with are collaborators. +If you want to create a project, skip down to [Create a +Project](#create-a-project). ## Step 1 - Select a Project -**Project** - *(e.g. Nonprofit Success Pack) Projects contain all the work being done. They are equivalent to GitHub repositories.* +**Project** - *(e.g. Nonprofit Success Pack) Projects contain all the work being +done. They are equivalent to GitHub repositories.* -- Select the Project you want to contribute to. -- If you do not see the Project you want to work on: +- Select the Project you want to contribute to. +- If you do not see the Project you want to work on: - Confirm that you are logged into the correct Metecho account. - - Contact an admin for the repository on GitHub and ensure that you are a collaborator. + - Contact an admin for the repository on GitHub and ensure that you are a + collaborator. - Select Re-sync Projects in Metecho. -To continue, go to **Step 2 - Create a Task/s** or, if you have a set of several closely related Tasks in mind, skip to [Step 13 - Create an Epic/s](#step-13---create-an-epics) +To continue, go to **Step 2 - Create a Task** or, if you have a set of several +closely related Tasks in mind, skip to [Step 13 - Create an +Epic](#step-13---create-an-epic) -## Step 2 - Create a Task/s -**Task** - *Tasks represent small changes to the Project, and may stand alone or be part of an Epic. Creating a Task creates a branch in GitHub.* +## Step 2 - Create a Task +**Task** - *Tasks represent small changes to the Project, and may stand alone or +be part of an Epic. Creating a Task creates a branch in GitHub.* -- Select the Tasks tab. +- Select the Tasks tab. - Create a new Task of your own (or from an existing GitHub Issue). - - Name the Task. -- The name can be a brief description of the work. -- Use the optional description section for more detail, if needed. -- Use the recommended dev org type unless you know of a specific reason to use a different one. -- Select Create to save and navigate to your Task detail view. Select Create & New to continue creating multiple Tasks that are unrelated to each other. -- If you need to edit the Task name or description, or delete the Task, select the gear icon in the top right corner. Deleting a Task deletes all the Orgs as well. - -## Step 3 - Invite Task Developer/s -**Developer** - *The person invited to do the work of a Task.* - -- Assign yourself or invite another person to be the Developer for each Task you created. -- Invited Developers will see an alert in Metecho and receive an email invitation. They need to accept the invitation if they want to begin development on the Task. -- If you do not see the person you want to invite, contact an admin for the repository on GitHub and ensure that the person is a collaborator. Then re-sync GitHub collaborators in Metecho. -- If you need to change or remove the Task Developer, use the drop down menu on the Developer card in the Task detail view. + - Name the Task. + - The name can be a brief description of the work. + - Use the optional description section for more detail, if needed. + - Use the recommended dev org type unless you know of a specific reason to use + a different one. + - Select Create to save and navigate to your Task detail view. Select Create & + New to continue creating multiple Tasks that are unrelated to each other. +- If you need to edit the Task name or description, or delete the Task, select + the gear icon in the top right corner. Deleting a Task deletes all the Orgs as + well. + +## Step 3 - Assign Task Developer +**Developer** - *The person assigned to do the work of a Task.* + +- Assign yourself or another person to be the Developer for each Task you + created. +- If you do not see the person you want to assign, contact an admin for the + repository on GitHub and ensure that the person is a collaborator. Then + re-sync GitHub collaborators in Metecho. +- If you need to change or remove the Task Developer, use the drop down menu on + the Developer card in the Task detail view. ## Step 4 - Create Dev Org -**Dev Org** - *A temporary Salesforce org where a Developer can work on contributions to a Project. Dev Orgs expire after 30 days, and all unretrieved work is deleted.* +**Dev Org** - *A temporary Salesforce org where a Developer can work on +contributions to a Project. Dev Orgs expire after 30 days, and all unretrieved +work is deleted.* -- Review the Next Steps for This Task list to see progress and who is responsible for the next step. -- To begin work, the Developer will need to select Create Org in the Dev Org card. -- Dev Org creation can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the Dev Org is ready. +- Review the Next Steps for This Task list to see progress and who is + responsible for the next step. +- To begin work, the Developer will need to select Create Org in the Dev Org + card. +- Dev Org creation can take a number of minutes. Feel free to leave the page. + Metecho will provide an alert when the Dev Org is ready. ## Step 5 - Make Changes in Dev Org -- **This step takes place in the new Salesforce Dev Org, not in Metecho.** -- Select View Org on the Dev Org card to navigate out of Metecho and make your changes in the temporary Salesforce Dev Org. +- **This step takes place in the new Salesforce Dev Org, not in Metecho.** +- Select View Org on the Dev Org card to navigate out of Metecho and make your + changes in the temporary Salesforce Dev Org. ## Step 6 - Retrieve Changes from Dev Org -**Retrieve Changes** - *Pull the work you did in your Salesforce Dev Org into Metecho so that other people can review it. Developers may retrieve changes as many times as they like while they are working.* +**Retrieve Changes** - *Pull the work you did in your Salesforce Dev Org into +Metecho so that other people can review it. Developers may retrieve changes as +many times as they like while they are working.* -- When the Developer is ready to pull the Salesforce Dev Org work into Metecho, they need to select Check for Unretrieved Changes (button located just above the Developer card in the Task detail view). +- When the Developer is ready to pull the Salesforce Dev Org work into Metecho, + they need to select Check for Unretrieved Changes (button located just above + the Developer card in the Task detail view). - Select the location to retrieve changes. - - Use the preselected Package Directory unless you know of a specific reason to select a different option. -- Select the changes to retrieve (or ignore). + - Use the preselected Package Directory unless you know of a specific reason + to select a different option. +- Select the changes to retrieve (or ignore). - Create a commit message that briefly describes the changes. - Select Retrieve Selected Changes. -- Retrieving changes can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the changes have been retrieved. -- Note that the Developer, commit message, and date now appear in a Commit History list in the Task detail view. +- Retrieving changes can take a number of minutes. Feel free to leave the page. + Metecho will provide an alert when the changes have been retrieved. +- Note that the Developer, commit message, and date now appear in a Commit + History list in the Task detail view. ## Step 7 - Submit Task Changes for Testing -**Submit Changes** - *Document all the changes a Developer made in a Salesforce Dev Org so that a Tester can test the work and leave a review. This action creates a pull request in GitHub.* - -**Pull Request** - *A way to propose changes on GitHub so that the maintainers of a Project can review them and accept the changes or request revisions.* - -- When the Developer is finished working and retrieving changes, they need to select Submit Task for Testing (button located just above the Developer card in the Task detail view). -- Each commit message briefly described what changed. Now, when submitting the Task for testing, describe all the critical changes and why they were made so the Tester will understand how to test them. +**Submit Changes** - *Document all the changes a Developer made in a Salesforce +Dev Org so that a Tester can test the work and leave a review. This action +creates a pull request in GitHub.* + +**Pull Request** - *A way to propose changes on GitHub so that the maintainers +of a Project can review them and accept the changes or request revisions.* + +- When the Developer is finished working and retrieving changes, they need to + select Submit Task for Testing (button located just above the Developer card + in the Task detail view). +- Each commit message briefly described what changed. Now, when submitting the + Task for testing, describe all the critical changes and why they were made so + the Tester will understand how to test them. - Select Submit Task for Testing. -## Step 8 - Invite a Tester -**Tester** - *The person who will look at the Developer’s work, and then approve the work or request changes that must be addressed before the Task can be completed.* +## Step 8 - Assign a Tester +**Tester** - *The person who will look at the Developer’s work, and then approve +the work or request changes that must be addressed before the Task can be +completed.* -- Assign yourself or invite another person to be the Tester for each Task you created. -- Testers can be invited at any time and, just like Developers, they need to accept the invitation in order to begin testing. -- If you do not see the person you want to invite, contact an admin for the repository on GitHub and ensure that the person is a collaborator. Then re-sync GitHub collaborators in Metecho. -- If you need to change or remove the Task Tester, use the drop down menu on the Tester card in the Task detail view. +- Assign yourself or another person to be the Tester for each Task you created. +- Testers can be assigned at any time. +- If you do not see the person you want to assign, contact an admin for the + repository on GitHub and ensure that the person is a collaborator. Then + re-sync GitHub collaborators in Metecho. +- If you need to change or remove the Task Tester, use the drop down menu on the + Tester card in the Task detail view. ## Step 9 - Create Test Org -**Test Org** - *A temporary Salesforce org where the Tester can look over the Developer’s work on a specific Task. Test Orgs expire after 30 days.* +**Test Org** - *A temporary Salesforce org where the Tester can look over the +Developer’s work on a specific Task. Test Orgs expire after 30 days.* -- Remember, you can review the Next Steps for This Task list to see progress and who is responsible for the next step. -- To begin testing, a Task Tester will need to select Create Org in the Test Org card. -- Dev Org creation can take a number of minutes. Feel free to leave the page. Metecho will provide an alert when the Dev Org is ready. +- Remember, you can review the Next Steps for This Task list to see progress and + who is responsible for the next step. +- To begin testing, a Task Tester will need to select Create Org in the Test Org + card. +- Dev Org creation can take a number of minutes. Feel free to leave the page. + Metecho will provide an alert when the Dev Org is ready. ## Step 10 - Test Changes in Test Org -- **This step takes place in the new Salesforce Test Org, not in Metecho.** -- Select View Org on the Test Org card to navigate out of Metecho and test the Developer’s changes in the temporary Salesforce Test Org. +- **This step takes place in the new Salesforce Test Org, not in Metecho.** +- Select View Org on the Test Org card to navigate out of Metecho and test the + Developer’s changes in the temporary Salesforce Test Org. ## Step 11 - Submit a Review -- When the Tester is finished testing the Developer’s changes in the Test Org, select Submit Review on the Test Org card. +- When the Tester is finished testing the Developer’s changes in the Test Org, + select Submit Review on the Test Org card. - Select Approve if no more work is needed. - Select Request Changes if the Developer needs to make revisions. -- Leave a description, especially if there are still changes the Developer needs to make, so that the Developer understands what to do next. +- Leave a description, especially if there are still changes the Developer needs + to make, so that the Developer understands what to do next. - Leaving Delete Test Org checked makes sense in most cases. - If the changes are Approved, there is no longer any need for the Test Org. - - If the Developer needs to make changes, the Tester will need to create a new Test Org to see the newly retrieved changes. + - If the Developer needs to make changes, the Tester will need to create a new + Test Org to see the newly retrieved changes. - Select Submit Review. - - If any change needs to be made to the review, select Update Review in the Test Org card. + - If any change needs to be made to the review, select Update Review in the + Test Org card. ## Step 12 - Merge Pull Request on GitHub -**Merge** - *To add proposed changes to the Project on GitHub.* +**Merge** - *To add proposed changes to the Project on GitHub.* -- **This step takes place on GitHub, not in Metecho.** -- When the Task has been added to the Project on Github, the Task status will update to Complete. +- **This step takes place on GitHub, not in Metecho.** +- A contributor with write access to the GitHub repository will need to review + and merge the pull request. When the pull request has been merged on GitHub, + the Task status will update to Complete on Metecho. *** -## Step 13 - Create an Epic/s -**Epic** - *Major contributions to a Project that include more than one related Task. Epics are more than containers for multiple Tasks. Like Tasks, creating an Epic creates a branch in GitHub. Tasks that are part of an Epic create branches from the Epic branch in GitHub.* +## Step 13 - Create an Epic +**Epic** - *Major contributions to a Project that include more than one related +Task. Epics are more than containers for multiple Tasks. Like Tasks, creating an +Epic creates a branch in GitHub. Tasks that are part of an Epic create branches +from the Epic branch in GitHub.* -- Select the Epics tab. +- Select the Epics tab. - Create a new Epic of your own (or from an existing GitHub Issue). -- Name the Epic. +- Name the Epic. - The name can be a brief description of the work. -- Select create a branch on GitHub unless you know the name of a specific branch you would like to use. +- Select create a branch on GitHub unless you know the name of a specific branch + you would like to use. - Use the optional description section for more detail, if needed. - Select Create to save and navigate to your Epic detail view. -- If you need to edit the Epic name or description, or delete the Epic, select the gear icon in the top right corner. Deleting an Epic deletes all Tasks and Orgs as well. +- If you need to edit the Epic name or description, or delete the Epic, select + the gear icon in the top right corner. Deleting an Epic deletes all Tasks and + Orgs as well. ## Step 14 - Add Collaborators - Select Add or Remove Collaborators. - Select one or more Collaborators to do the work on the Tasks in this Epic. -- If you do not see the people you want to invite, contact an admin for the repository on GitHub and ensure that the people are collaborators. Then re-sync GitHub collaborators in Metecho. -- If you need to remove a collaborator, select the X icon in the Collaborator card or uncheck the box in the list of Collaborators. +- If you do not see the people you want to add, contact an admin for the + repository on GitHub and ensure that the people are collaborators. Then + re-sync GitHub collaborators in Metecho. +- If you need to remove a collaborator, select the X icon in the Collaborator + card or uncheck the box in the list of Collaborators. -To continue, go up to [Step 2 - Create a Task/s](#step-2---create-a-tasks) +To continue, go up to [Step 2 - Create a Task](#step-2---create-a-task) *** + ## Create a Project - In the Project list view, select Create Project. -- If you do not see the GitHub Organization you want to work in: +- If you do not see the GitHub Organization you want to work in: - Confirm that you are logged into the correct Metecho account. - - Contact an admin for the repository on GitHub and ensure that you are a collaborator. + - Contact an admin for the repository on GitHub and ensure that you are a + collaborator. - Select Re-sync GitHub Organizations. - Select a GitHub Organization. - Create a Project name. - Select people to add as Collaborators on the Project. -- If you do not see the people you want to invite, contact an admin for the repository on GitHub and ensure that the people are collaborators. Then re-sync GitHub collaborators in Metecho. -- Review your Project selections. Go Back to make edits, Cancel, or Create Project. +- If you do not see the people you want to add, contact an admin for the + repository on GitHub and ensure that the people are collaborators. Then + re-sync GitHub collaborators in Metecho. +- Review your Project selections. Go Back to make edits, Cancel, or Create + Project. -To continue, go up to [Step 2 - Create a Task/s](#step-2---create-a-tasks) or [Step 13 - Create an Epic/s](#step-13---create-an-epics) +To continue, go up to [Step 2 - Create a Task](#step-2---create-a-task) or +[Step 13 - Create an Epic](#step-13---create-an-epic) *** + ## Additional Help -**Select the ? menu** in the top right corner of Metecho at any time to: +**Select the ? menu** in the top right corner of Metecho at any time to: - View specific walkthroughs. -- Activate self-guided tour mode for more detail about everything Metecho can do for you. +- Activate self-guided tour mode for more detail about everything Metecho can do + for you. diff --git a/test/js/store/projects/actions.test.js b/test/js/store/projects/actions.test.js index e20dc56c1..0c93492ce 100644 --- a/test/js/store/projects/actions.test.js +++ b/test/js/store/projects/actions.test.js @@ -496,16 +496,16 @@ describe('refreshIssues', () => { url = window.api_urls.project_refresh_github_issues(projectId); }); - test('dispatches RefreshGithubIssues action', () => { + test('dispatches RefreshGitHubIssues action', () => { const store = storeWithThunk({}); fetchMock.postOnce(url, { status: 202, }); - const RefreshGithubIssuesRequested = { + const RefreshGitHubIssuesRequested = { type: 'REFRESH_GH_ISSUES_REQUESTED', payload: projectId, }; - const RefreshGithubIssuesAccepted = { + const RefreshGitHubIssuesAccepted = { type: 'REFRESH_GH_ISSUES_ACCEPTED', payload: projectId, }; @@ -513,8 +513,8 @@ describe('refreshIssues', () => { expect.assertions(1); return store.dispatch(actions.refreshGitHubIssues(projectId)).then(() => { expect(store.getActions()).toEqual([ - RefreshGithubIssuesRequested, - RefreshGithubIssuesAccepted, + RefreshGitHubIssuesRequested, + RefreshGitHubIssuesAccepted, ]); }); }); From 3d09ca654c806a83fed522287b82e7b807b062f5 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Tue, 14 Jun 2022 16:43:45 +0200 Subject: [PATCH 22/62] Lint fix --- src/js/utils/api.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/utils/api.ts b/src/js/utils/api.ts index 453739c7a..71c5c69e2 100644 --- a/src/js/utils/api.ts +++ b/src/js/utils/api.ts @@ -3,7 +3,6 @@ import { isUndefined } from 'lodash'; import { ThunkDispatch } from 'redux-thunk'; import { addError } from '@/js/store/errors/actions'; -import { ObjectTypes } from '@/js/utils/constants'; import { logError } from '@/js/utils/logging'; interface UrlParams { From 323267eba8cad11109b915eafa6903c64f829262 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Tue, 14 Jun 2022 10:57:09 -0400 Subject: [PATCH 23/62] review --- docs/metecho-how-to.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/metecho-how-to.md b/docs/metecho-how-to.md index eac7a5ce2..9e53dce82 100644 --- a/docs/metecho-how-to.md +++ b/docs/metecho-how-to.md @@ -80,7 +80,8 @@ many times as they like while they are working.* - Select the location to retrieve changes. - Use the preselected Package Directory unless you know of a specific reason to select a different option. -- Select the changes to retrieve (or ignore). +- Select the changes to retrieve (or ignore changes you do not intend to + retrieve). - Create a commit message that briefly describes the changes. - Select Retrieve Selected Changes. - Retrieving changes can take a number of minutes. Feel free to leave the page. @@ -125,8 +126,8 @@ Developer’s work on a specific Task. Test Orgs expire after 30 days.* who is responsible for the next step. - To begin testing, a Task Tester will need to select Create Org in the Test Org card. -- Dev Org creation can take a number of minutes. Feel free to leave the page. - Metecho will provide an alert when the Dev Org is ready. +- Test Org creation can take a number of minutes. Feel free to leave the page. + Metecho will provide an alert when the Test Org is ready. ## Step 10 - Test Changes in Test Org - **This step takes place in the new Salesforce Test Org, not in Metecho.** @@ -166,12 +167,12 @@ from the Epic branch in GitHub.* - Select the Epics tab. - Create a new Epic of your own (or from an existing GitHub Issue). -- Name the Epic. + - Name the Epic. - The name can be a brief description of the work. -- Select create a branch on GitHub unless you know the name of a specific branch - you would like to use. -- Use the optional description section for more detail, if needed. -- Select Create to save and navigate to your Epic detail view. + - Select create a branch on GitHub unless you know the name of a specific + branch you would like to use. + - Use the optional description section for more detail, if needed. + - Select Create to save and navigate to your Epic detail view. - If you need to edit the Epic name or description, or delete the Epic, select the gear icon in the top right corner. Deleting an Epic deletes all Tasks and Orgs as well. @@ -199,11 +200,12 @@ To continue, go up to [Step 2 - Create a Task](#step-2---create-a-task) - Select a GitHub Organization. - Create a Project name. - Select people to add as Collaborators on the Project. -- If you do not see the people you want to add, contact an admin for the - repository on GitHub and ensure that the people are collaborators. Then - re-sync GitHub collaborators in Metecho. -- Review your Project selections. Go Back to make edits, Cancel, or Create - Project. + - If you do not see the people you want to add, contact an admin for the + repository on GitHub and ensure that the people are collaborators. Then + re-sync GitHub collaborators in Metecho. +- Select any dependencies for your new Project. +- Review your Project selections. Select Create to save and navigate to your + Project detail view. To continue, go up to [Step 2 - Create a Task](#step-2---create-a-task) or [Step 13 - Create an Epic](#step-13---create-an-epic) From 142e0a4506193014c9de081e55356f14a3eb46dd Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Tue, 14 Jun 2022 11:06:29 -0400 Subject: [PATCH 24/62] review --- docs/component-library-how-to.md | 37 +++++++++++++------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/docs/component-library-how-to.md b/docs/component-library-how-to.md index 01b68022f..96903a0c9 100644 --- a/docs/component-library-how-to.md +++ b/docs/component-library-how-to.md @@ -4,7 +4,7 @@ The Metecho component library is a source for developers and non-developers alike to get a quick overview of how components that make up the project behave and appear. -Components used in in the project are custom versions of +Components used in the project are custom versions of [SLDS components](https://react.lightningdesignsystem.com/). The library was created with [Storybook](https://storybook.js.org/) @@ -18,14 +18,12 @@ similarly to how the original components are organized in `src/js/components`. For example, the component library version of the modal for creating a new **Epic**, the `createForm` component, would be found in the `epics/` directory: - src/ stories/ epics/ - createForm/ - index.stories.mdx - index.stories.tsx - + createForm/ + index.stories.mdx + index.stories.tsx Each component folder consists of two files. The `.mdx` file is where documentation for each component is stored. The rendering of the component, with @@ -41,8 +39,9 @@ In general, this consists of: - Importing the component from `src/js/components` - Setting where and how Storybook lists the component with a -[default export](https://storybook.js.org/docs/react/writing-stories/introduction#default-export) -- [Creating a template](https://storybook.js.org/docs/react/writing-stories/introduction#default-export) for how `args` map to rendering + [default export](https://storybook.js.org/docs/react/writing-stories/introduction#default-export) +- [Creating a template](https://storybook.js.org/docs/react/writing-stories/introduction#default-export) + for how `args` map to rendering - Setting the component `args` and `argTypes` - Naming the component story by setting a `storyName` @@ -50,34 +49,28 @@ In general, this consists of: To view changes while you work on the library, use one of the below commands: - $ ./derrick storybook # if running outside of container - $ yarn storybook # if working in a remote container in VS Code + $ ./derrick storybook # to run Storybook inside a Docker container + $ yarn storybook # to run Storybook locally, outside a Docker container -After running one of these commands, you can view the Storybook at +After running one of these commands, you can view the library at in your browser. # Decorators -If a component needs to be wrapped in a -[decorator](https://storybook.js.org/docs/react/writing-stories/decorators), -first import the mock Redux store: - +If a component relies on the Redux store, it must be wrapped in a +[decorator](https://storybook.js.org/docs/react/writing-stories/decorators). +First import the mock Redux store: import { withRedux } from '../decorators'; - - and then add a `decorators` prop to the default export: - export default { title: 'Commits/List/Example', component: CommitListComponent, decorators: [withRedux()], }; - - ## Sample Data Some components require sample data and props to function correctly. This data, @@ -106,10 +99,10 @@ and states are written as `code`. Through [Storybook Deployer](https://github.com/storybookjs/storybook-deployer), the library is set to deploy automatically as a static site to Github Pages each -time a commit is made to the main branch. +time a commit is made to the `main` branch. The workflow for this job is located in `.github/workflows/deploy-storybook.yml` Additional core Storybook configuration settings (i.e. global decorators and parameters, webpack configuration, story loading, etc.) can be found in the -`.storybook` directory. +`.storybook/` directory. From 0f8c70c23ecc27bac5c903636a5e4bc41cfb1e41 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Tue, 14 Jun 2022 17:12:26 +0200 Subject: [PATCH 25/62] fix link --- docs/component-library-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/component-library-how-to.md b/docs/component-library-how-to.md index 01b68022f..7288d9538 100644 --- a/docs/component-library-how-to.md +++ b/docs/component-library-how-to.md @@ -42,7 +42,7 @@ In general, this consists of: - Importing the component from `src/js/components` - Setting where and how Storybook lists the component with a [default export](https://storybook.js.org/docs/react/writing-stories/introduction#default-export) -- [Creating a template](https://storybook.js.org/docs/react/writing-stories/introduction#default-export) for how `args` map to rendering +- [Creating a template](https://storybook.js.org/docs/react/writing-stories/introduction#using-args) for how `args` map to rendering - Setting the component `args` and `argTypes` - Naming the component story by setting a `storyName` From 5518e43703088b15ea5411b42e42fb183af6c1c8 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Tue, 14 Jun 2022 17:46:58 +0200 Subject: [PATCH 26/62] Frontend code review edits - user dropdown, helper function --- src/js/components/user/info.tsx | 9 ++++++++- src/js/components/utils/deleteModal.tsx | 13 ++++--------- src/js/store/actions.ts | 4 ++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/js/components/user/info.tsx b/src/js/components/user/info.tsx index 087849f87..cc58343d1 100644 --- a/src/js/components/user/info.tsx +++ b/src/js/components/user/info.tsx @@ -240,6 +240,10 @@ const UserDropdown = () => { const { t } = useTranslation(); const user = useSelector(selectUserState); const [modalOpen, setModalOpen] = useState(false); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const toggleDropdown = () => { + setIsDropdownOpen(!isDropdownOpen); + }; if (!user) { return null; @@ -248,6 +252,8 @@ const UserDropdown = () => { return ( <> @@ -287,7 +293,8 @@ const UserDropdown = () => { {user.username}
- | + |{' '} +
diff --git a/src/js/components/utils/deleteModal.tsx b/src/js/components/utils/deleteModal.tsx index 81b55877e..a081cdd2d 100644 --- a/src/js/components/utils/deleteModal.tsx +++ b/src/js/components/utils/deleteModal.tsx @@ -21,14 +21,6 @@ interface Props extends RouteComponentProps { handleClose: () => void; } -const getModelDeleteUrl = (modelType: ObjectTypes) => { - let deleteUrl; - if (modelType === 'user') { - deleteUrl = window.api_urls.current_user_detail(); - } - return deleteUrl; -}; - const DeleteModal = ({ model, modelType, @@ -48,7 +40,10 @@ const DeleteModal = ({ deleteObject({ objectType: modelType, object: model, - url: getModelDeleteUrl(modelType), + url: + modelType === OBJECT_TYPES.USER + ? window.api_urls.current_user_detail() + : undefined, }), ) .then(() => { diff --git a/src/js/store/actions.ts b/src/js/store/actions.ts index b9ea40805..a26921736 100644 --- a/src/js/store/actions.ts +++ b/src/js/store/actions.ts @@ -2,7 +2,7 @@ import { ThunkResult } from '@/js/store'; import { Epic } from '@/js/store/epics/reducer'; import { Task } from '@/js/store/tasks/reducer'; import apiFetch, { addUrlParams } from '@/js/utils/api'; -import { ObjectTypes } from '@/js/utils/constants'; +import { OBJECT_TYPES, ObjectTypes } from '@/js/utils/constants'; interface CreateObjectPayload { objectType?: ObjectTypes; @@ -335,7 +335,7 @@ export const deleteObject = id: object.id, }); } - if (objectType === 'user') { + if (objectType === OBJECT_TYPES.USER) { return dispatch({ type: 'USER_LOGGED_OUT' as const, payload: { objectType, url, object }, From 96536f4baa0a58779e0d23f705e2c06043bb9f27 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Tue, 14 Jun 2022 13:23:47 -0400 Subject: [PATCH 27/62] also close dropdown on connect-to-sf click --- src/js/components/user/info.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/js/components/user/info.tsx b/src/js/components/user/info.tsx index cc58343d1..ab892d114 100644 --- a/src/js/components/user/info.tsx +++ b/src/js/components/user/info.tsx @@ -24,13 +24,16 @@ import { selectUserState } from '@/js/store/user/selectors'; const ConnectToSalesforce = ({ toggleModal, + closeDropdown, }: { toggleModal: React.Dispatch>; + closeDropdown: () => void; }) => { const { t } = useTranslation(); const openConnectModal = () => { toggleModal(true); + closeDropdown(); }; return ( @@ -244,6 +247,9 @@ const UserDropdown = () => { const toggleDropdown = () => { setIsDropdownOpen(!isDropdownOpen); }; + const closeDropdown = () => { + setIsDropdownOpen(false); + }; if (!user) { return null; @@ -254,6 +260,7 @@ const UserDropdown = () => { @@ -304,7 +311,10 @@ const UserDropdown = () => { {user.valid_token_for || user.devhub_username ? ( ) : ( - + )} )} From 00a008dfc11f8b6e6e6453dd7bd417a6d497c84d Mon Sep 17 00:00:00 2001 From: dvdherron Date: Wed, 15 Jun 2022 13:28:07 +0200 Subject: [PATCH 28/62] fix link --- docs/component-library-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/component-library-how-to.md b/docs/component-library-how-to.md index 9b8789897..e1a6c4264 100644 --- a/docs/component-library-how-to.md +++ b/docs/component-library-how-to.md @@ -79,7 +79,7 @@ Storybook defaults to showing each component prop as a control for each component in the library. For this project, props that are less relevant to the various states of the component have been disabled. Props more relevant to state and display are set with appropriate -[control types](https://storybook.js.org/docs/react/essentials/controls#choosing-the-control-type. +[control types](https://storybook.js.org/docs/react/essentials/controls#choosing-the-control-type). ## Documenting Components From 9e066182af85e6eba9372e723e913257d45cad57 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Wed, 15 Jun 2022 18:44:50 +0200 Subject: [PATCH 29/62] Dropdown style changes --- src/js/components/user/info.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/js/components/user/info.tsx b/src/js/components/user/info.tsx index ab892d114..e2de35c6e 100644 --- a/src/js/components/user/info.tsx +++ b/src/js/components/user/info.tsx @@ -40,7 +40,7 @@ const ConnectToSalesforce = ({ <>