diff --git a/assets/cloud_project_page.png b/assets/cloud_project_page.png new file mode 100644 index 0000000000..6f346810b9 Binary files /dev/null and b/assets/cloud_project_page.png differ diff --git a/assets/hosting_adding_team_members.png b/assets/hosting_adding_team_members.png new file mode 100644 index 0000000000..5550e10ddd Binary files /dev/null and b/assets/hosting_adding_team_members.png differ diff --git a/assets/hosting_tokens.png b/assets/hosting_tokens.png new file mode 100644 index 0000000000..ee254632f1 Binary files /dev/null and b/assets/hosting_tokens.png differ diff --git a/docs/hosting/additional-concepts.md b/docs/hosting/additional-concepts.md new file mode 100644 index 0000000000..c265bb688a --- /dev/null +++ b/docs/hosting/additional-concepts.md @@ -0,0 +1,209 @@ +```python exec +import reflex as rx +from reflex_image_zoom import image_zoom +from pcweb.pages import docs +from pcweb.styles.styles import get_code_style, cell_style + + +regions = { + "ams": "Amsterdam, Netherlands", + "arn": "Stockholm, Sweden", + "alt": "Atlanta, Georgia (US)", + "bog": "Bogotá, Colombia", + "bom": "Mumbai, India", + "bos": "Boston, Massachusetts (US)", + "cdg": "Paris, France", + "den": "Denver, Colorado (US)", + "dfw": "Dallas, Texas (US)", + "ewr": "Secaucus, NJ (US)", + "eze": "Ezeiza, Argentina", + "fra": "Frankfurt, Germany", + "gdl": "Guadalajara, Mexico", + "gig": "Rio de Janeiro, Brazil", + "gru": "Sao Paulo, Brazil", + "hkg": "Hong Kong, Hong Kong", + "iad": "Ashburn, Virginia (US)", + "jnb": "Johannesburg, South Africa", + "lax": "Los Angeles, California (US)", + "lhr": "London, United Kingdom", + "mad": "Madrid, Spain", + "mia": "Miami, Florida (US)", + "nrt": "Tokyo, Japan", + "ord": "Chicago, Illinois (US)", + "otp": "Bucharest, Romania", + "phx": "Phoenix, Arizona (US)", + "qro": "Querétaro, Mexico", + "scl": "Santiago, Chile", + "sea": "Seattle, Washington (US)", + "sin": "Singapore, Singapore", + "sjc": "San Jose, California (US)", + "syd": "Sydney, Australia", + "waw": "Warsaw, Poland", + "yul": "Montreal, Canada", + "yyz": "Toronto, Canada" +} + +vmtypes = [ + {"id": "c1m.5", "name": "Single CPU Small", "cpu_cores": 1, "ram_gb": 0.512}, + {"id": "c1m1", "name": "Single CPU Medium", "cpu_cores": 1, "ram_gb": 1.024}, + {"id": "c1m2", "name": "Single CPU Large", "cpu_cores": 1, "ram_gb": 2.048}, + {"id": "c2m.5", "name": "Double CPU Micro", "cpu_cores": 2, "ram_gb": 0.512}, + {"id": "c2m1", "name": "Double CPU Small", "cpu_cores": 2, "ram_gb": 1.024}, + {"id": "c2m2", "name": "Double CPU Medium", "cpu_cores": 2, "ram_gb": 2.048}, + {"id": "c2m4", "name": "Double CPU Large", "cpu_cores": 2, "ram_gb": 4.096}, + {"id": "c4m1", "name": "Quad CPU Micro", "cpu_cores": 4, "ram_gb": 1.024}, + {"id": "c4m2", "name": "Quad CPU Small", "cpu_cores": 4, "ram_gb": 2.048}, + {"id": "c4m4", "name": "Quad CPU Medium", "cpu_cores": 4, "ram_gb": 4.096}, + {"id": "c4m8", "name": "Quad CPU Large", "cpu_cores": 4, "ram_gb": 8.192} +] + +``` + + +# Reflex Cloud - Additional Concepts + +To go back, i.e. from an app to a project or from a project to your list of projects you just click the `REFLEX logo` in the top left corner of the page. + +```md alert info +# All flag values are saved between runs +All your flag values, i.e. environment variables or regions or tokens, are saved between runs. This means that if you run a command and you pass a flag value, the next time you run the same command the flag value will be the same as the last time you ran it. This means you should only set the flag values again if you want to change them. +``` + +## Environment Variables + + +Below is an example of how to use an environment variable file. You can pass the `--envfile` flag with the path to the env file. For example: + +```bash +reflex deploy --project f88b1574-f101-####-####-5f########## --envfile .env +``` + +In this example the path to the file is `.env`. + + +If you prefer to pass the environment variables manually below is deployment command example: + +```bash +reflex deploy --project f88b1574-f101-####-####-5f########## --env OPENAI_API_KEY=sk-proj-vD4i9t6U############################ +``` + +They are passed after the `--env` flag as key value pairs. + +To pass multiple environment variables, you can repeat the `--env` tag. i.e. `reflex deploy --project f88b1574-f101-####-####-5f########## --env KEY1=VALUE1 --env KEY2=VALUE`. The `--envfile` flag will override any envs set manually. + + +```md alert info +# More information on Environment Variables +Environment variables are encrypted and safely stored. We recommend that backend API keys or secrets are entered as `envs`. Make sure to enter the `envs` without any quotation marks. We do not show the values of them in any CLI commands, only their names (or keys). + +You access the values of `envs` by referencing `os.environ` with their names as keys in your app's backend. For example, if you set an env `ASYNC_DB_URL`, you are able to access it by `os.environ["ASYNC_DB_URL"]`. Some Python libraries automatically look for certain environment variables. For example, `OPENAI_API_KEY` for the `openai` python client. The `boto3` client credentials can be configured by setting `AWS_ACCESS_KEY_ID`,`AWS_SECRET_ACCESS_KEY`. This information is typically available in the documentation of the Python packages you use. +``` + +## Adding Team Members + +If you are a User you have the ability to create, deploy and delete apps, but you do not have the power to add or delete users from that project. You must be an Admin for that. + +As an Admin you will see the an `Add user` button in the top right of the screen, as shown in the image below. Clicking on this will allow you to add a user to the project. You will need to enter the email address of the user you wish to add. + +```python eval +image_zoom(rx.image(src="/hosting_adding_team_members.png", alt="Adding team members to Reflex Cloud")) +``` + +```python eval +rx.box(height="20px") +``` + +```md alert warning +# Currently a User must already have logged in once before they can be added to a project. +At this time a User must be logged in to be added to a project. In future there will be automatic email invites sent to add new users who have never logged in before. +``` + + + + + +## Tokens + +A token gives someone else all the permissions you have as a User or an Admin. They can run any Reflex Cloud command from the CLI as if they are you using the `--token` flag. A good use case would be for GitHub actions (you store this token in the secrets). + +Tokens are found on the Project List page. If you cannot find it click the Reflex Logo in the top left side of the page until it appears as in the image below. + +```python eval +image_zoom(rx.image(src="/hosting_tokens.png", alt="Adding tokens to Reflex Cloud")) +``` + + +## VMTypes + +To get all the possible VMTypes you can run the following command: + +```bash +reflex apps vmtypes +``` + +To set which VMType to use when deploying your app you can pass the `--vmtype` flag with the id of the VMType. For example: + +```bash +reflex deploy --project f88b1574-f101-####-####-5f########## --vmtype c2m4 +``` + +This will deploy your app with the `c2m4` VMType, giving your app 2 cpu cores and 4 gb of ram. + +Below is a table of all the possible VMTypes: + +```python eval +rx.table.root( + rx.table.header( + rx.table.row( + rx.table.column_header_cell("id"), + rx.table.column_header_cell("name"), + rx.table.column_header_cell("cpu (cores)"), + rx.table.column_header_cell("ram (gb)"), + ), + ), + rx.table.body( + *[ + rx.table.row( + rx.table.cell(rx.code(vmtype["id"], style=get_code_style("violet"))), + rx.table.cell(vmtype["name"], style=cell_style), + rx.table.cell(vmtype["cpu_cores"], style=cell_style), + rx.table.cell(vmtype["ram_gb"], style=cell_style), + ) + for vmtype in vmtypes + ] + ), + variant="surface", +) +``` + +## Regions + +Below is an example of how to deploy your app in several regions: + +```bash +reflex deploy --project f88b1574-f101-####-####-5f########## --region sjc --region iad +``` + +By default all apps are deloyed in `sjc` if no other regions are given. If you wish to deploy in another region or several regions you can pass the `--region` flag (`-r` also works) with the region code. Check out all the regions that we can deploy to below: + + +```python eval +rx.table.root( + rx.table.header( + rx.table.row( + rx.table.column_header_cell("Region Code"), + rx.table.column_header_cell("Region"), + ), + ), + rx.table.body( + *[ + rx.table.row( + rx.table.cell(rx.code(region_code, style=get_code_style("violet"))), + rx.table.cell(region_name, style=cell_style), + ) + for region_code, region_name in regions.items() + ] + ), + variant="surface", +) +``` \ No newline at end of file diff --git a/docs/hosting/deploy-quick-start.md b/docs/hosting/deploy-quick-start.md index 41a69988d5..baa0baae36 100644 --- a/docs/hosting/deploy-quick-start.md +++ b/docs/hosting/deploy-quick-start.md @@ -1,10 +1,9 @@ -# Reflex Hosting Service +# Reflex Cloud - Quick Start ```python exec import reflex as rx -from pcweb import constants +from reflex_image_zoom import image_zoom from pcweb.pages import docs -from pcweb.templates.docpage import doccmdoutput ``` So far, we have been running our apps locally on our own machines. @@ -17,13 +16,14 @@ Reflex’s hosting service makes it easy to deploy your apps without worrying ab ### Prerequisites -1. Hosting service requires `reflex>=0.6.5`. +1. Hosting service requires `reflex>=0.6.6`. 2. This tutorial assumes you have successfully `reflex init` and `reflex run` your app. -3. Also make sure you have a `requirements.txt` file at the top level app directory that contains all your python dependencies! +3. Also make sure you have a `requirements.txt` file at the top level app directory that contains all your python dependencies! (To create a `requirements.txt` file, run `pip freeze > requirements.txt`.) + ### Authentication -First, create an account or log into it using the following command. +First run the command below to login / signup to your Reflex Cloud account: (command line) ```bash reflex login @@ -31,56 +31,44 @@ reflex login You will be redirected to your browser where you can authenticate through Github or Gmail. +### Web UI + +Once you are at this URL and you have successfully authenticated, click on the one project you have in your workspace. You should get a screen like this: + +```python eval +image_zoom(rx.image(src="/cloud_project_page.png", alt="Reflex Cloud Dashboard")) +``` + +This screen shows the login command and the deploy command. As we are already logged in, we can skip the login command. + ### Deployment -Once you have successfully authenticated, you can start deploying your apps. +Now you can start deploying your app. -Navigate to the project directory that you want to deploy and type the following command: +In your cloud UI copy the `reflex deploy` command similar to the one shown below. ```bash -reflex deploy +reflex deploy --project 2a432b8f-2605-4753-####-####0cd1#### ``` -The command is by default interactive. It asks you a few questions for information required for the deployment. - -**Name**: choose a name for the deployed app. This name will be part of the deployed app URL, i.e. `-randomword-randomword.reflex.run`. +In your project directory (where you would normally run `reflex run`) paste this command. -The name should only contain domain name safe characters: no slashes, no underscores. +The command is by default interactive. It asks you a few questions for information required for the deployment. -```md alert info -# Custom domains are available for paid plans. -``` -**Regions**: enter the region code here or press `Enter` to accept the default. The default code `sjc` stands for San Jose, California in the US west coast. Check the list of supported regions at [reflex deployments regions](#reflex-deployments-regions). +1. The first question will compare your `requirements.txt` to your python environment and if they are different then it will ask you if you want to update your `requirements.txt` or to continue with the current one. If they are identical this queston will not appear. To create a `requirements.txt` file, run `pip freeze > requirements.txt`. +2. The second question will search for a deployed app with the name of your current app, if it does not find one then it will ask if you wish to proceed in deploying your new app. +3. The third question is optional and will ask you for an app description. -**Envs**: `Envs` are environment variables. You might not have used them at all in your app. In that case, press `Enter` to skip. More on the environment variables in the later section [Environment Variables](#environment-variables). That’s it! You should receive some feedback on the progress of your deployment and in a few minutes your app should be up. 🎉 ```md alert info -# The hosting service does not currently handle database or file upload operations. Set up an external database and use it within your app. +# Once your code is uploaded, the hosting service will start the deployment. After a complete upload, exiting from the command **does not** affect the deployment process. The command prints a message when you can safely close it without affecting the deployment. ``` -## See it in Action +If you go back to the Cloud UI you should be able to see your deployed app and other useful app information. + + -Below is a video of deploying the [AI chat app]({docs.getting_started.chatapp_tutorial.path}) to our hosting service. -```python eval -rx.box( - rx.el.iframe( - src="https://www.loom.com/embed/bee928924a454a8098e741e1d19b2857?sid=38523a3f-4c7d-4ee2-9a51-4ca1a36828dc", - frameborder="0", - webkitallowfullscreen=True, - mozallowfullscreen=True, - allowfullscreen=True, - position="absolute", - top="0", - left="0", - width="100%", - height="100%", - ), - position="relative", - padding_bottom="64.94708994708994%", - height="0", -) -``` diff --git a/docs/hosting/deploy-with-github-actions.md b/docs/hosting/deploy-with-github-actions.md new file mode 100644 index 0000000000..51f4de4f59 --- /dev/null +++ b/docs/hosting/deploy-with-github-actions.md @@ -0,0 +1,118 @@ +```python exec +from pcweb.pages import docs +import reflex as rx +from pcweb.styles.styles import get_code_style, cell_style + +github_actions_configs = [ + { + "name": "auth_token", + "description": "Reflex authentication token stored in GitHub Secrets.", + "required": True, + "default": "N/A" + }, + { + "name": "project_id", + "description": "The ID of the project you want to deploy to.", + "required": True, + "default": "N/A" + }, + { + "name": "app_directory", + "description": "The directory containing your Reflex app.", + "required": False, + "default": ". (root)" + }, + { + "name": "extra_args", + "description": "Additional arguments to pass to the `reflex deploy` command.", + "required": False, + "default": "N/A" + }, + { + "name": "python_version", + "description": "The Python version to use for the deployment environment.", + "required": False, + "default": "3.9" + } +] +``` + +# Reflex Deploy with Github Actions + +This GitHub Action simplifies the deployment of Reflex applications to Reflex Cloud. It handles setting up the environment, installing the Reflex CLI, and deploying your app with minimal configuration. + +```md alert info +# This action requires `reflex>=0.6.6` +``` + +**Features:** +- Deploy Reflex apps directly from your GitHub repository to Reflex Cloud. +- Supports subdirectory-based app structures. +- Securely uses authentication tokens via GitHub Secrets. + +## Usage +### Add the Action to Your Workflow +Create a `.github/workflows/deploy.yml` file in your repository and add the following: + +```yaml +name: Deploy Reflex App + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Deploy to Reflex Cloud + uses: reflex-dev/reflex-deploy-action@v1 + with: + auth_token: ${\{ secrets.REFLEX_PROJECT_ID }} + project_id: ${\{ secrets.REFLEX_PROJECT_ID }} + app_directory: "my-app-folder" # Optional, defaults to root + extra_args: "--env THIRD_PARTY_APIKEY=***" # Optional + python_version: "3.12" # Optional +``` + +### Set Up Your Secrets +Store your Reflex authentication token securely in your repository's secrets: + + +1. Go to your GitHub repository. +2. Navigate to Settings > Secrets and variables > Actions > New repository secret. +3. Create new secrets for `REFLEX_AUTH_TOKEN` and `REFLEX_PROJECT_ID`. + +(Create a `REFLEX_AUTH_TOKEN` in the tokens tab of your UI, check out these [docs]({docs.hosting.additional_concepts.path}#tokens). + +The `REFLEX_PROJECT_ID` can be found in the UI when you click on the How to deploy button on the top right when inside a project and copy the ID after the `--project` flag.) + + + +### Inputs + +```python eval +rx.table.root( + rx.table.header( + rx.table.row( + rx.table.column_header_cell("Name"), + rx.table.column_header_cell("Description"), + rx.table.column_header_cell("required"), + rx.table.column_header_cell("Default"), + ), + ), + rx.table.body( + *[ + rx.table.row( + rx.table.cell(rx.code(github_config["name"], style=get_code_style("violet"))), + rx.table.cell(github_config["description"], style=cell_style), + rx.table.cell(rx.code(github_config["required"], style=get_code_style("violet"))), + rx.table.cell(rx.code(github_config["default"], style=get_code_style("violet")), min_width="100px"), + ) + for github_config in github_actions_configs + ] + ), + variant="surface", +) +``` \ No newline at end of file diff --git a/docs/hosting/hosting-cli-commands.md b/docs/hosting/hosting-cli-commands.md index ca2214065b..e69de29bb2 100644 --- a/docs/hosting/hosting-cli-commands.md +++ b/docs/hosting/hosting-cli-commands.md @@ -1,168 +0,0 @@ -# Reflex Hosting Service CLI Commands - -```python exec -import reflex as rx -from pcweb import constants -from pcweb.templates.docpage import doccmdoutput -from pcweb.styles.styles import get_code_style, cell_style - - -regions = { - "alt": "Atlanta, Georgia (US)", - "bog": "Bogotá, Colombia", - "bos": "Boston, Massachusetts (US)", - "cdg": "Paris, France", - "den": "Denver, Colorado (US)", - "dfw": "Dallas, Texas (US)", - "eze": "Ezeiza, Argentina", - "fra": "Frankfurt, Germany", - "hkg": "Hong Kong, Hong Kong", - "iad": "Ashburn, Virginia (US)", - "lax": "Los Angeles, California (US)", - "lhr": "London, United Kingdom", - "mad": "Madrid, Spain", - "mia": "Miami, Florida (US)", - "ord": "Chicago, Illinois (US)", - "scl": "Santiago, Chile", - "sea": "Seattle, Washington (US)", - "sin": "Singapore, Singapore", - "sjc": "San Jose, California (US)", - "syd": "Sydney, Australia", - "waw": "Warsaw, Poland", - "yul": "Montreal, Canada", - "yyz": "Toronto, Canada" -} -``` - -## Concepts - -### Requirements - -To be able to deploy your app, we ask that you prepare a `requirements.txt` file containing all the required Python packages for it. The hosting service runs a `pip install` command based on this file to prepare the instances that run your app. We recommend that you use a Python virtual environment when starting a new app, and only install the necessary packages. This reduces the preparation time installing no more packages than needed, and your app is deployed faster. There are a lot of resources online on Python virtual environment tools and how to capture the packages in a `requirements.txt` file. - -### Environment Variables - -When deploying to Reflex's hosting service, the command prompt asks if you want to add any environment variables. These are encrypted and safely stored. We recommend that backend API keys or secrets are entered as `envs`. Make sure to enter the `envs` without any quotation marks. - -The environment variables are key value pairs. We do not show the values of them in any CLI commands, only their names (or keys). However, if your app intentionally prints the values of these variables, the logs returned still contain the printed values. At the moment, the logs are not censored for anything resembling secrets. Only the app owner and Reflex team admins can access these logs. - -You access the values of `envs` by referencing `os.environ` with their names as keys in your app's backend. For example, if you set an env `ASYNC_DB_URL`, you are able to access it by `os.environ["ASYNC_DB_URL"]`. Some Python libraries automatically look for certain environment variables. For example, `OPENAI_API_KEY` for the `openai` python client. The `boto3` client credentials can be configured by setting `AWS_ACCESS_KEY_ID`,`AWS_SECRET_ACCESS_KEY`. This information is typically available in the documentation of the Python packages you use. - -### Updating Deployment - -To redeploy or update your app, navigate to the project directory and type `reflex deploy` again. This command communicates with the hosting service to automatically detect your existing app with the same name. This time the deploy command overwrites the app. You should see a prompt similar to `Overwrite deployment [ app-name ] ...`. This operation is a complete overwrite and not an incremental update. - -## CLI Command Reference - -All the `reflex` commands come with a help manual. The help manual lists additional command options that may be useful. You type `--help` to see the help manual. Some commands are organized under a `subcommands` series. Here is an example below. Note that the help manual may look different depending on the version of `reflex` or the `reflex-hosting-cli`. - -``` bash -reflex deployments --help -``` - -### Authentication Commands - -#### reflex login - -When you type the `reflex login` command for the very first time, it opens the hosting service login page in your browser. We authenticate users through OAuth. At the moment the supported OAuth providers are Github and Gmail. You should be able to revoke such authorization on your Github and Google account settings page. We do not log into your Github or Gmail account. OAuth authorization provides us your email address and in case of Github your username handle. We use those to create an account for you. The email used in the original account creation is used to identify you as a user. If you have authenticated using different emails, those create separate accounts. To switch to another account, first log out using the `reflex logout` command. More details on the logout command are in [reflex logout](#reflex-logout) section. - -``` bash -reflex login -``` - -After authentication, the browser redirects to the original hosting service login page. It shows that you have logged in. Now you can return to the terminal where you type the login command. It should print a message such as `Successfully logged in`. - -Your access token is cached locally in the reflex support directory. For subsequent login commands, the cached token is validated first. If the token is still valid, the CLI command simply shows `You’re already logged in`. If the token is expired or simply not valid for any reason, the login command tries to open your browser again for web based authentication. - -#### reflex logout - -When you successfully authenticate with the hosting service, there is information cached in two different places: a file containing the access token in the reflex support directory, and cookies in your browser. The cookies include the access token, a refresh token, some unix epochs indicating when the access token expires. The logout command removes the cached information from these places. - -### Deployment Commands - -#### reflex deploy - -This is the command to deploy a reflex app from its top level app directory. This directory contains a `rxconfig.py` where you run `reflex init` and `reflex run`. - -A `requirements.txt` file is required. The deploy command checks the content of this file against the top level packages installed in your current Python environment. If the command detects new packages in your Python environment, or newer versions of the same packages, it prints the difference and asks if you would like to update your `requirements.txt`. Make sure you double check the suggested updates. This functionality is added in more recent versions of the hosting CLI package `reflex-hosting-cli>=0.1.3`. - -``` bash -reflex deploy -``` - -The deploy command is by default interactive. To deploy without interaction, add `--no-interactive` and set the relevant command options as deployment settings. Type `reflex deploy --help` to see the help manual for explanations on each option. The deploy sequences are the same, whether the deploy command is interactive or not. - -```bash -reflex deploy --no-interactive -k todo -r sjc -r sea --env OPENAI_API_KEY=YOU-KEY-NO-EXTRA-QUOTES --env DB_URL=YOUR-EXTERNAL-DB-URI --env KEY3=THATS-ALOTOF-KEYS -``` - -#### reflex deployments list - -List all your deployments. - -``` bash -reflex deployments list -``` - -#### reflex deployments status `app-name` - -Get the status of a specific app, including backend and frontend. - -``` bash -reflex deployments status clock-gray-piano -``` - -#### reflex deployments logs `app-name` - -Get the logs from a specific deployment. - -The returned logs are the messages printed to console. If you have `print` statements in your code, they show up in these logs. By default, the logs command return the latest 100 lines of logs and continue to stream any new lines. - -We have added more options to this command including `from` and `to` timestamps and the limit on how many lines of logs to fetch. Accepted timestamp formats include the ISO 8601 format, unix epoch and relative timestamp. A relative timestamp is some time units ago from `now`. The units are `d (day), h (hour), m (minute), s (second)`. For example, `--from 3d --to 4h` queries from 3 days ago up to 4 hours ago. For the exact syntax in the version of CLI you use, refer to the help manual. - -``` bash -reflex deployments logs todo -``` - -#### reflex deployments build-logs `app-name` - -Get the logs of the hosting service deploying the app. - -``` bash -reflex deployments build-logs webcam-demo -``` - -The hosting service prints log messages when preparing and deploying your app. These log messages are called build logs. Build logs are useful in troubleshooting deploy failures. For example, if there is a package `numpz==1.26.3` (supposed to be `numpy`) in the `requirements.txt`, hosting service will be unable to install it. That package does not exist. We expect to find a few lines in the build logs indicating that the `pip install` command fails. - -#### reflex deployments delete `app-name` - -Delete a specific deployment. - -### Public Commands - -These commands do not require authentication. - -#### reflex deployments regions - -List all the valid regions to select for a deployment. - -```python eval -rx.table.root( - rx.table.header( - rx.table.row( - rx.table.column_header_cell("Region Code"), - rx.table.column_header_cell("Region"), - ), - ), - rx.table.body( - *[ - rx.table.row( - rx.table.cell(rx.code(region_code, style=get_code_style("violet"))), - rx.table.cell(region_name, style=cell_style), - ) - for region_code, region_name in regions.items() - ] - ), - variant="surface", -) -``` diff --git a/pcweb/components/docpage/sidebar/sidebar.py b/pcweb/components/docpage/sidebar/sidebar.py index 68d52b253d..2b90a26d5c 100644 --- a/pcweb/components/docpage/sidebar/sidebar.py +++ b/pcweb/components/docpage/sidebar/sidebar.py @@ -112,7 +112,8 @@ def sidebar_icon(name): "Database": "database", "Authentication": "lock-keyhole", "Utility Methods": "cog", - "Reflex Deploy": "earth", + "Quick Start": "earth", + "CLI Reference": "square-terminal", "Self Hosting": "server", "Custom Components": "blocks", } diff --git a/pcweb/components/docpage/sidebar/sidebar_items/learn.py b/pcweb/components/docpage/sidebar/sidebar_items/learn.py index f9a9d04935..cde06102cf 100644 --- a/pcweb/components/docpage/sidebar/sidebar_items/learn.py +++ b/pcweb/components/docpage/sidebar/sidebar_items/learn.py @@ -1,3 +1,4 @@ +from pcweb.pages.docs import cloud_cliref from .item import create_item @@ -200,12 +201,17 @@ def get_sidebar_items_hosting(): items = [ create_item( - "Reflex Deploy", + "Quick Start", children=[ hosting.deploy_quick_start, - hosting.hosting_cli_commands, + hosting.additional_concepts, + hosting.deploy_with_github_actions, ], ), + create_item( + "CLI Reference", + children=cloud_cliref.pages + ), create_item( "Self Hosting", children=[hosting.self_hosting], diff --git a/pcweb/pages/docs/__init__.py b/pcweb/pages/docs/__init__.py index 1f13fa4e89..39ad4223ed 100644 --- a/pcweb/pages/docs/__init__.py +++ b/pcweb/pages/docs/__init__.py @@ -21,6 +21,7 @@ from .recipes_overview import overview from .custom_components import custom_components from .apiref import pages as apiref_pages +from .cloud_cliref import pages as cloud_cliref_pages from pcweb.pages.library_previews import components_previews_pages @@ -187,13 +188,17 @@ def get_component(doc: str, title: str): custom_components, overview, *components_previews_pages, -] + apiref_pages +] + apiref_pages + cloud_cliref_pages for api_route in apiref_pages: title = rx.utils.format.to_snake_case(api_route.title) build_nested_namespace(docs_ns, ["api_reference"], title, api_route) +for api_route in cloud_cliref_pages: + title = rx.utils.format.to_snake_case(api_route.title) + build_nested_namespace(docs_ns, ["api_reference"], title, api_route) + for doc in sorted(flexdown_docs): path = doc.split("/")[1:-1] diff --git a/pcweb/pages/docs/cloud_cliref.py b/pcweb/pages/docs/cloud_cliref.py new file mode 100644 index 0000000000..2946745f88 --- /dev/null +++ b/pcweb/pages/docs/cloud_cliref.py @@ -0,0 +1,104 @@ +import subprocess +import tempfile +import os +import re +from pcweb.templates.docpage import docpage +import reflex as rx + +def get_command_help_output(path_to_file: str = None, name_of_cli_program: str = "reflex") -> str: + # Create a temporary file + with tempfile.NamedTemporaryFile(delete=False, suffix=".md") as temp_file: + temp_file_path = temp_file.name + + try: + # Run the command and save the output to the temporary file + result = subprocess.run( + [ + "typer", path_to_file, "utils", "docs", + "--name", name_of_cli_program, "--output", temp_file_path + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + # Check if the command ran successfully + if result.returncode != 0: + print("Error running command:", result.stderr) + return None + + # Read the content from the temporary file + with open(temp_file_path, 'r') as file: + output = file.read() + + finally: + # Clean up and delete the temporary file + if os.path.exists(temp_file_path): + os.remove(temp_file_path) + + # Return the content of the temporary file + return output + +# Get the help output +deploy_subcommands_output = get_command_help_output(path_to_file="reflex_cli.v2.deployments", name_of_cli_program="reflex apps") +reflexpy_output = get_command_help_output(path_to_file="reflex.reflex") + +# Dictionary to store the parsed documentation +docs_dict = {} + +# Regular expression to capture each section +pattern_deploy_subcommands = r"## `reflex apps (.*?)`\n(.*?)(?=\n## `reflex apps|\Z)" +pattern_reflexpy = r"## `reflex (.*?)`\n(.*?)(?=\n## `reflex|\Z)" + +matches_deploy_subcommands = re.finditer(pattern_deploy_subcommands, deploy_subcommands_output, re.DOTALL) +matches_reflexpy = re.finditer(pattern_reflexpy, reflexpy_output, re.DOTALL) + +# Iterate over all matches and populate the dictionary +for match in matches_deploy_subcommands: + command_name = match.group(1).strip() + command_doc = match.group(2).strip().replace("<", "<").replace(">", ">") + docs_dict[command_name] = command_doc + +for match in matches_reflexpy: + command_name = match.group(1).strip() + command_doc = match.group(2).strip().replace("<", "<").replace(">", ">") + docs_dict[command_name] = command_doc + +# Dictionary to store the categories and their respective commands +categories = { + "login": ["loginv2", "logoutv2"], + "deploy": ["deployv2"], + "apps": ["status", "start", "stop", "scale", "delete", "logs", "history"], + "project": ["project-list", "project-create", "project-select", "project-invite", + "project-get-select", "project-usage", "project-role-permissions", "project-users"], + "secrets": ["secrets-list", "secrets-delete", "secrets-update"], + "vmtypes": ["vmtypes"], + "regions": ["regions"], +} + +# Dictionary to store the combined documentation for each category +modules = {} + +# Extract and combine documentation for each category +for category, commands in categories.items(): + docs_list = [ + f"# {command}\n\n{docs_dict[command]}" + for command in commands if command in docs_dict + ] + modules[category] = "\n\n".join(docs_list) + +from pcweb.flexdown import markdown + +def generate_docs(source: str): + return rx.box( + markdown(text=source), + ) + + +pages = [] +for module_name, module_value in modules.items(): + docs = generate_docs(module_value) + title = module_name.replace("_", " ").title() + page_data = docpage(f"/docs/hosting/{module_name}/", title)(docs) + page_data.title = page_data.title.split('·')[0].strip() + pages.append(page_data) \ No newline at end of file