diff --git a/.gitignore b/.gitignore index fe232bd..9a61dfd 100644 --- a/.gitignore +++ b/.gitignore @@ -176,4 +176,3 @@ examples/**/poetry.lock # playground folder for previewing templates .playground/* -!.playground/.gitkeep diff --git a/.playground/.gitkeep b/.playground/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 3e2db20..1c954aa 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -8,7 +8,7 @@ "-v", "init", "--name", - "test_output", + ".playground", "--no-git", "--UNSAFE-SECURITY-accept-template-url", "--template-url", @@ -18,13 +18,13 @@ "--no-bootstrap" ], "type": "shell", - "dependsOn": ["Delete test_output folder"], + "dependsOn": ["Delete .playground folder"], "problemMatcher": [] }, { - "label": "Delete test_output folder", + "label": "Delete .playground folder", "command": "rm", - "args": ["-rf", "test_output"], + "args": ["-rf", ".playground"], "type": "shell", "windows": { "command": "./.vscode/clear.ps1" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6a13bbd..22ebaaa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,23 +5,36 @@ This repository is a template for creating new AlgoKit projects. It includes a b ## Pre-requisites `poetry install` - Install the dependencies for the project. +`pipx install algokit` - Ensure cli is installed. ## Testing ```bash -poetry run pytest +poetry run pytest -n auto ``` -This will regenerate the tests for default `starter` and `production` presets as well as default tests for `generators` available on the template. +This will regenerate the tests for default `starter` and `production` presets. ## Development +### Manual + ```bash -poetry run copier copy . .playground/{some_dummy_folder_name} --vcs-ref=HEAD --trust +poetry run copier copy . .playground --vcs-ref=HEAD --trust ``` To generate a dummy project into the `.playground` folder. This is useful for testing the template to quickly preview the output of the template before testing via `pytest`. +### Using VSCode Tasks + +In VSCode IDE, you can find the tasks in the `.vscode/tasks.json` file. To run them: + +1. Open the command palette (`Cmd+Shift+P` on macOS, `Ctrl+Shift+P` on Windows/Linux) and type `> Run Task` +2. Select the task you want to run +3. It will be generated for you under the .playground folder + +To cleanup the .playground folder run dedicated cleanup task. + ## Contributing ### Commits diff --git a/copier.yaml b/copier.yaml index 040d741..35ff11b 100644 --- a/copier.yaml +++ b/copier.yaml @@ -1,7 +1,12 @@ _subdirectory: template_content _templates_suffix: '.jinja' -# questions +use_workspace: + type: bool + when: false # never prompted to user explicitly, instead expect cli to auto fill (supported cli versions > v1.13.x) + help: Automatically filled by AlgoKit CLI (>1.13.x) - passes the --workspace/--no-workspace flag's value, can be used to reason whether this template is currently being instantiated as part of a workspace or not. + default: no + # project_name should never get prompted, AlgoKit should always pass it by convention project_name: type: str @@ -18,6 +23,7 @@ author_email: help: Package author email placeholder: 'your@email.tld' +# Preset related questions preset_name: type: str help: Name of the template preset to use. diff --git a/examples/cloud_provider/.gitkeep b/examples/cloud_provider/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/examples/cloud_provider/production_react_netlify/.algokit.toml b/examples/cloud_provider/production_react_netlify/.algokit.toml index 754e2a4..27cc0d6 100644 --- a/examples/cloud_provider/production_react_netlify/.algokit.toml +++ b/examples/cloud_provider/production_react_netlify/.algokit.toml @@ -1,5 +1,5 @@ [algokit] -min_version = "v1.3.0b1" +min_version = "v2.0.0" [generate.import_contract] description = "Import a typed client from your smart contracts project" @@ -7,4 +7,15 @@ path = ".algokit/generators/import_contract" [project] type = "frontend" -name = "production_react_netlify" +name = 'production_react_netlify' +artifacts = "src/contracts" + +[project.run] +build = { commands = ['npm run build'], description = 'Build frontend' } +test = { commands = ['npm run test'], description = 'Run frontend tests' } +lint = { commands = ['npm run lint'], description = 'Lint frontend code' } +ci-deploy-netlify = { commands = [ + 'npm install --global netlify-cli@latest', + 'netlify login', + 'netlify deploy --build --prod' + ], description = 'Deploy to Netlify' } diff --git a/examples/cloud_provider/production_react_netlify/.github/workflows/checks.yaml b/examples/cloud_provider/production_react_netlify/.github/workflows/checks.yaml deleted file mode 100644 index 4723b1a..0000000 --- a/examples/cloud_provider/production_react_netlify/.github/workflows/checks.yaml +++ /dev/null @@ -1,54 +0,0 @@ -name: Check code base - -on: - workflow_call: - inputs: - run-build: - required: false - type: boolean - default: false - push: - branches: - - main - -jobs: - checks: - runs-on: 'ubuntu-latest' - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Install dependencies - run: npm ci - - - name: Run linters - run: npm run lint - - - name: Run unit tests - run: npm run test - - - name: Create placeholder .env file - if: ${{ inputs.run-build }} - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build - if: ${{ inputs.run-build }} - run: npm run build - - - name: Archive - if: ${{ inputs.run-build }} - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ diff --git a/examples/cloud_provider/production_react_netlify/.github/workflows/pr.yaml b/examples/cloud_provider/production_react_netlify/.github/workflows/pr.yaml deleted file mode 100644 index a80f784..0000000 --- a/examples/cloud_provider/production_react_netlify/.github/workflows/pr.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Pull Request validation - -on: [pull_request] - -jobs: - pr-check: - name: Perform Checks - uses: ./.github/workflows/checks.yaml diff --git a/examples/cloud_provider/production_react_netlify/.github/workflows/production-react-netlify-cd.yaml b/examples/cloud_provider/production_react_netlify/.github/workflows/production-react-netlify-cd.yaml new file mode 100644 index 0000000..6cd8222 --- /dev/null +++ b/examples/cloud_provider/production_react_netlify/.github/workflows/production-react-netlify-cd.yaml @@ -0,0 +1,53 @@ +name: Release production_react_netlify + +on: + workflow_call: + push: + branches: + - main + paths-ignore: + - "docs/**" + - "**.md" + - ".vscode/**" + - ".idea/**" + +permissions: + contents: read + packages: read + +jobs: + validate: + name: Validate production_react_netlify + uses: ./.github/workflows/production-react-netlify-ci.yaml + deploy: + runs-on: ubuntu-latest + name: Deploy to Netlify + environment: frontend-prod + + needs: + - validate + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install algokit + run: pipx install algokit + + - name: Bootstrap dependencies + run: algokit bootstrap all --project-name 'production_react_netlify' + + - name: Publish to Netlify + env: + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + run: | + npm install --global netlify-cli@latest + netlify login + netlify deploy --build --prod + \ No newline at end of file diff --git a/examples/cloud_provider/production_react_netlify/.github/workflows/production-react-netlify-ci.yaml b/examples/cloud_provider/production_react_netlify/.github/workflows/production-react-netlify-ci.yaml new file mode 100644 index 0000000..e0f0241 --- /dev/null +++ b/examples/cloud_provider/production_react_netlify/.github/workflows/production-react-netlify-ci.yaml @@ -0,0 +1,48 @@ +name: Validate production_react_netlify + +on: + + workflow_call: + pull_request: + + +jobs: + validate: + runs-on: 'ubuntu-latest' + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install poetry + run: pipx install poetry + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "poetry" + + - name: Install algokit + run: pipx install algokit + + - name: Install dependencies + run: algokit bootstrap all --project-name 'production_react_netlify' + + + - name: Run linters + run: algokit project run lint --project-name 'production_react_netlify' + + + - name: Run unit tests + run: algokit project run test --project-name 'production_react_netlify' + + + - name: Build + run: algokit project run build --project-name 'production_react_netlify' diff --git a/examples/cloud_provider/production_react_netlify/.github/workflows/release.yaml b/examples/cloud_provider/production_react_netlify/.github/workflows/release.yaml deleted file mode 100644 index ffff1bf..0000000 --- a/examples/cloud_provider/production_react_netlify/.github/workflows/release.yaml +++ /dev/null @@ -1,65 +0,0 @@ -name: Release - -on: - push: - branches: - - main - paths-ignore: - - "docs/**" - - "**.md" - - ".vscode/**" - - ".idea/**" - -permissions: - contents: read - packages: read - -jobs: - lint-and-build: - name: CI dApp - uses: ./.github/workflows/checks.yaml - with: - run-build: true - - - deploy: - runs-on: ubuntu-latest - name: Deploy to Netlify - environment: Prod - concurrency: "${{ github.workflow }}-prod" - needs: - - lint-and-build - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: dist - path: dist - - - name: Replace template vars - uses: makerxstudio/shared-config/.github/actions/placeholder-transforms@main - with: - app-artifact-path: './dist' - static-site-transforms: |- - VITE_ALGOD_TOKEN:${{ secrets.VITE_ALGOD_TOKEN }} - VITE_ALGOD_SERVER:${{ vars.VITE_ALGOD_SERVER }} - VITE_ALGOD_PORT:${{ vars.VITE_ALGOD_PORT }} - VITE_ALGOD_NETWORK:${{ vars.VITE_ALGOD_NETWORK }} - VITE_INDEXER_SERVER:${{ vars.VITE_INDEXER_SERVER }} - VITE_INDEXER_PORT:${{ vars.VITE_INDEXER_PORT }} - VITE_INDEXER_TOKEN:${{ secrets.VITE_INDEXER_TOKEN }} - VITE_ENVIRONMENT:${{ vars.VITE_ENVIRONMENT }} - - - name: Install netlify cli - run: npm i netlify-cli - - - name: Publish to netlify - run: netlify deploy --prod --dir "dist" - env: - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - # Set your netlify project env variables on your github repository (see README for more info) - diff --git a/examples/cloud_provider/production_react_netlify/.gitignore b/examples/cloud_provider/production_react_netlify/.gitignore index 26dc019..b1ce837 100644 --- a/examples/cloud_provider/production_react_netlify/.gitignore +++ b/examples/cloud_provider/production_react_netlify/.gitignore @@ -33,3 +33,6 @@ yarn-error.log* !.idea/ .idea/* !.idea/runConfigurations/ + +.vercel +.netlify diff --git a/examples/cloud_provider/production_react_netlify/README.md b/examples/cloud_provider/production_react_netlify/README.md index 4ba1c7e..1284030 100644 --- a/examples/cloud_provider/production_react_netlify/README.md +++ b/examples/cloud_provider/production_react_netlify/README.md @@ -33,7 +33,7 @@ This starter React project has been generated using AlgoKit. See below for defau ### Continuous Integration -This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI workflows, which are located in the [`.github/workflows`](./.github/workflows) folder. +This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI workflows, which are located in the [.github/workflows](`.github/workflows`) folder. For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions: @@ -41,6 +41,8 @@ For pull requests and pushes to `main` branch against this repository the follow - `lint`: Lints the codebase using `ESLint` - `build`: Builds the codebase using `vite` +> Please note, if you instantiated the project via `algokit init` without explicitly specifying the `--no-workspace` flag, we will automatically attempt to move the contents of the `.github` folder to the root of the workspace. + ### Continuous Deployment The project template provides base Github Actions workflows for continuous deployment to [Netlify](https://www.netlify.com/) or [Vercel](https://vercel.com/). These workflows are located in the [`.github/workflows`](./.github/workflows) folder. @@ -50,20 +52,24 @@ The project template provides base Github Actions workflows for continuous deplo #### Setting up environment variables and secrets for webapp deployment -1. [Create a new environment variable on your repository](https://docs.github.com/en/actions/learn-github-actions/variables#creating-configuration-variables-for-a-repository) called `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` if you are using Netlify as your cloud provider. Set it to the value of your Netlify auth token respectively. You can find your Netlify auth token by going to [app.netlify.com](https://app.netlify.com/). -2. If you are using Vercel as your cloud provider, create a new environment variable on your repository called `VERCEL_TOKEN`. Set it to the value of your Vercel auth token. You can find your Vercel auth token by going to [vercel.com/account/tokens](https://vercel.com/account/tokens). -3. Set up the environment variables. You can refer to the `.env.template` for default values. The variables to be set are: - - `VITE_ALGOD_SERVER` - - `VITE_ALGOD_NETWORK` - - `VITE_INDEXER_SERVER` - - `VITE_ENVIRONMENT` - (Set to either `production` or `development`) - - `VITE_ALGOD_PORT` - (This is optional if you are using a public gateway like AlgoNode) - - `VITE_INDEXER_PORT` - (This is optional if you are using a public gateway like AlgoNode) -4. (Optional) If you need to set up environment secrets, you can do so by following the guide [here](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository). The variables for which you can set secrets are (refer to `.env.template` for default values): - - `VITE_ALGOD_TOKEN` - (This is optional if you are using a public gateway like AlgoNode) - - `VITE_INDEXER_TOKEN` - (This is optional if you are using a public gateway like AlgoNode) - -> If you prefer alternative deployment methods, you can remove the relevant workflow files from the [`.github/workflows`](./.github/workflows) folder and configure your own. +For Vercel: +1. Retrieve your [Vercel Access Token](https://vercel.com/support/articles/how-do-i-use-a-vercel-api-access-token) +2. Install the [Vercel CLI](https://vercel.com/cli) and run `vercel login` +3. Inside your folder, run `vercel link` to create a new Vercel project +4. Inside the generated `.vercel` folder, save the `projectId` and `orgId` from the `project.json` +5. Inside GitHub, add `VERCEL_TOKEN`, `VERCEL_ORG_ID`, and `VERCEL_PROJECT_ID` as [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +6. Create an .env file containing ENV vars for the project (pointing to testnet or mainnet), drag and drop the .env file to upload initial batch of default environment variables to your vercel project. +7. Upon invocation, CD pipeline will pull the VITE_ prefixed environment variables, build the project and deploy to the specified environment. + +For Netlify: +1. Retrieve your [Netlify Access Token](https://docs.netlify.com/cli/get-started/#obtain-a-token-in-the-netlify-ui) +2. Inside your folder run `netlify login` +3. Inside your folder run `netlify sites:create` to create a new site, obtain NETLIFY_SITE_ID from the output +4. Inside GitHub, add `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` as [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +5. Define the VITE_ prefixed environment variables in netlify environment variables under site settings. +6. Upon invocation, CD pipeline will build the project and deploy to the specified environment. + +> If you prefer alternative deployment methods, you can modify the relevant workflow files from the [`.github/workflows`](./.github/workflows) folder or modify deploy scripts in `.algokit.toml`. # Algorand Wallet integrations diff --git a/examples/cloud_provider/production_react_netlify/package.json b/examples/cloud_provider/production_react_netlify/package.json index 217bd77..df4293e 100644 --- a/examples/cloud_provider/production_react_netlify/package.json +++ b/examples/cloud_provider/production_react_netlify/package.json @@ -46,8 +46,9 @@ "tslib": "^2.6.2" }, "scripts": { - "dev": "vite", - "build": "tsc && vite build", + "generate:app-clients": "algokit project link --all", + "dev": "npm run generate:app-clients && vite", + "build": "npm run generate:app-clients && tsc && vite build", "test": "jest --coverage --passWithNoTests", "playwright:test": "playwright test", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", diff --git a/examples/cloud_provider/production_react_netlify/src/contracts/README.md b/examples/cloud_provider/production_react_netlify/src/contracts/README.md index e056b58..04629b1 100644 --- a/examples/cloud_provider/production_react_netlify/src/contracts/README.md +++ b/examples/cloud_provider/production_react_netlify/src/contracts/README.md @@ -4,10 +4,11 @@ The following folder is reserved for the Algorand Application Clients. The clien To integrate this react frontend template with your smart contracts codebase, perform the following steps: -1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` +1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` or using the dedicated `link` command `algokit project link` (ensure to invoke it from the root of this react project). Using the `link` command is especially useful within workspaces that have multiple contract projects. 2. The generated typescript client should be ready to be imported and used in this react frontend template, making it a full fledged dApp. -### FAQ +> Please note, by default this template defines `"generate:app-clients": "algokit project link --all"` which is a shortcut to automatically link TEAL code from all `contract` projects in the workspace as typed clients into the `frontend` project that is invoking the `link` command. Refer to [documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/project/link.md) to read more about `link` command. -- **How to interact with the smart contract?** - - The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. +## **How to interact with the smart contract?** + +The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. diff --git a/examples/cloud_provider/production_react_vercel/.algokit.toml b/examples/cloud_provider/production_react_vercel/.algokit.toml index f3abe6e..9ef3814 100644 --- a/examples/cloud_provider/production_react_vercel/.algokit.toml +++ b/examples/cloud_provider/production_react_vercel/.algokit.toml @@ -1,5 +1,5 @@ [algokit] -min_version = "v1.3.0b1" +min_version = "v2.0.0" [generate.import_contract] description = "Import a typed client from your smart contracts project" @@ -7,4 +7,15 @@ path = ".algokit/generators/import_contract" [project] type = "frontend" -name = "production_react_vercel" +name = 'production_react_vercel' +artifacts = "src/contracts" + +[project.run] +build = { commands = ['npm run build'], description = 'Build frontend' } +test = { commands = ['npm run test'], description = 'Run frontend tests' } +lint = { commands = ['npm run lint'], description = 'Lint frontend code' } +ci-deploy-vercel = { commands = [ + 'npm install --global vercel@latest', + 'npm run ci:vercel:pull', + 'npm run ci:vercel:deploy', + ], description = 'Deploy to Vercel' } diff --git a/examples/cloud_provider/production_react_vercel/.github/workflows/checks.yaml b/examples/cloud_provider/production_react_vercel/.github/workflows/checks.yaml deleted file mode 100644 index 4723b1a..0000000 --- a/examples/cloud_provider/production_react_vercel/.github/workflows/checks.yaml +++ /dev/null @@ -1,54 +0,0 @@ -name: Check code base - -on: - workflow_call: - inputs: - run-build: - required: false - type: boolean - default: false - push: - branches: - - main - -jobs: - checks: - runs-on: 'ubuntu-latest' - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Install dependencies - run: npm ci - - - name: Run linters - run: npm run lint - - - name: Run unit tests - run: npm run test - - - name: Create placeholder .env file - if: ${{ inputs.run-build }} - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build - if: ${{ inputs.run-build }} - run: npm run build - - - name: Archive - if: ${{ inputs.run-build }} - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ diff --git a/examples/cloud_provider/production_react_vercel/.github/workflows/pr.yaml b/examples/cloud_provider/production_react_vercel/.github/workflows/pr.yaml deleted file mode 100644 index a80f784..0000000 --- a/examples/cloud_provider/production_react_vercel/.github/workflows/pr.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Pull Request validation - -on: [pull_request] - -jobs: - pr-check: - name: Perform Checks - uses: ./.github/workflows/checks.yaml diff --git a/examples/cloud_provider/production_react_vercel/.github/workflows/production-react-vercel-cd.yaml b/examples/cloud_provider/production_react_vercel/.github/workflows/production-react-vercel-cd.yaml new file mode 100644 index 0000000..2a2648f --- /dev/null +++ b/examples/cloud_provider/production_react_vercel/.github/workflows/production-react-vercel-cd.yaml @@ -0,0 +1,55 @@ +name: Release production_react_vercel + +on: + workflow_call: + push: + branches: + - main + paths-ignore: + - "docs/**" + - "**.md" + - ".vscode/**" + - ".idea/**" + +permissions: + contents: read + packages: read + +jobs: + validate: + name: Validate production_react_vercel + uses: ./.github/workflows/production-react-vercel-ci.yaml + deploy: + runs-on: ubuntu-latest + name: Deploy to Vercel + environment: frontend-prod + + needs: + - validate + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install algokit + run: pipx install algokit + + - name: Bootstrap dependencies + run: algokit bootstrap all --project-name 'production_react_vercel' + + - name: Publish to Vercel + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + run: | + npm install --global vercel@canary + vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} + vercel build --prod + vercel deploy --prebuilt --prod + \ No newline at end of file diff --git a/examples/cloud_provider/production_react_vercel/.github/workflows/production-react-vercel-ci.yaml b/examples/cloud_provider/production_react_vercel/.github/workflows/production-react-vercel-ci.yaml new file mode 100644 index 0000000..dce0309 --- /dev/null +++ b/examples/cloud_provider/production_react_vercel/.github/workflows/production-react-vercel-ci.yaml @@ -0,0 +1,48 @@ +name: Validate production_react_vercel + +on: + + workflow_call: + pull_request: + + +jobs: + validate: + runs-on: 'ubuntu-latest' + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install poetry + run: pipx install poetry + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "poetry" + + - name: Install algokit + run: pipx install algokit + + - name: Install dependencies + run: algokit bootstrap all --project-name 'production_react_vercel' + + + - name: Run linters + run: algokit project run lint --project-name 'production_react_vercel' + + + - name: Run unit tests + run: algokit project run test --project-name 'production_react_vercel' + + + - name: Build + run: algokit project run build --project-name 'production_react_vercel' diff --git a/examples/cloud_provider/production_react_vercel/.github/workflows/release.yaml b/examples/cloud_provider/production_react_vercel/.github/workflows/release.yaml deleted file mode 100644 index 13152f1..0000000 --- a/examples/cloud_provider/production_react_vercel/.github/workflows/release.yaml +++ /dev/null @@ -1,66 +0,0 @@ -name: Release - -on: - push: - branches: - - main - paths-ignore: - - "docs/**" - - "**.md" - - ".vscode/**" - - ".idea/**" - -permissions: - contents: read - packages: read - -jobs: - lint-and-build: - name: CI dApp - uses: ./.github/workflows/checks.yaml - - deploy: - runs-on: ubuntu-latest - name: Deploy to Vercel - environment: Prod - concurrency: "${{ github.workflow }}-prod" - needs: - - lint-and-build - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Install Vercel CLI - run: npm install --global vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - - name: Create placeholder .env file - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - - name: Replace template vars - uses: makerxstudio/shared-config/.github/actions/placeholder-transforms@main - with: - app-artifact-path: './.vercel/output' - static-site-transforms: |- - VITE_ALGOD_TOKEN:${{ secrets.VITE_ALGOD_TOKEN }} - VITE_ALGOD_SERVER:${{ vars.VITE_ALGOD_SERVER }} - VITE_ALGOD_PORT:${{ vars.VITE_ALGOD_PORT }} - VITE_ALGOD_NETWORK:${{ vars.VITE_ALGOD_NETWORK }} - VITE_INDEXER_SERVER:${{ vars.VITE_INDEXER_SERVER }} - VITE_INDEXER_PORT:${{ vars.VITE_INDEXER_PORT }} - VITE_INDEXER_TOKEN:${{ secrets.VITE_INDEXER_TOKEN }} - VITE_ENVIRONMENT:${{ vars.VITE_ENVIRONMENT }} - - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} - # Set your vercel project env variables on your github repository (see README for more info) - diff --git a/examples/cloud_provider/production_react_vercel/.gitignore b/examples/cloud_provider/production_react_vercel/.gitignore index 26dc019..b1ce837 100644 --- a/examples/cloud_provider/production_react_vercel/.gitignore +++ b/examples/cloud_provider/production_react_vercel/.gitignore @@ -33,3 +33,6 @@ yarn-error.log* !.idea/ .idea/* !.idea/runConfigurations/ + +.vercel +.netlify diff --git a/examples/cloud_provider/production_react_vercel/README.md b/examples/cloud_provider/production_react_vercel/README.md index 6853822..1253777 100644 --- a/examples/cloud_provider/production_react_vercel/README.md +++ b/examples/cloud_provider/production_react_vercel/README.md @@ -33,7 +33,7 @@ This starter React project has been generated using AlgoKit. See below for defau ### Continuous Integration -This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI workflows, which are located in the [`.github/workflows`](./.github/workflows) folder. +This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI workflows, which are located in the [.github/workflows](`.github/workflows`) folder. For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions: @@ -41,6 +41,8 @@ For pull requests and pushes to `main` branch against this repository the follow - `lint`: Lints the codebase using `ESLint` - `build`: Builds the codebase using `vite` +> Please note, if you instantiated the project via `algokit init` without explicitly specifying the `--no-workspace` flag, we will automatically attempt to move the contents of the `.github` folder to the root of the workspace. + ### Continuous Deployment The project template provides base Github Actions workflows for continuous deployment to [Netlify](https://www.netlify.com/) or [Vercel](https://vercel.com/). These workflows are located in the [`.github/workflows`](./.github/workflows) folder. @@ -50,20 +52,24 @@ The project template provides base Github Actions workflows for continuous deplo #### Setting up environment variables and secrets for webapp deployment -1. [Create a new environment variable on your repository](https://docs.github.com/en/actions/learn-github-actions/variables#creating-configuration-variables-for-a-repository) called `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` if you are using Netlify as your cloud provider. Set it to the value of your Netlify auth token respectively. You can find your Netlify auth token by going to [app.netlify.com](https://app.netlify.com/). -2. If you are using Vercel as your cloud provider, create a new environment variable on your repository called `VERCEL_TOKEN`. Set it to the value of your Vercel auth token. You can find your Vercel auth token by going to [vercel.com/account/tokens](https://vercel.com/account/tokens). -3. Set up the environment variables. You can refer to the `.env.template` for default values. The variables to be set are: - - `VITE_ALGOD_SERVER` - - `VITE_ALGOD_NETWORK` - - `VITE_INDEXER_SERVER` - - `VITE_ENVIRONMENT` - (Set to either `production` or `development`) - - `VITE_ALGOD_PORT` - (This is optional if you are using a public gateway like AlgoNode) - - `VITE_INDEXER_PORT` - (This is optional if you are using a public gateway like AlgoNode) -4. (Optional) If you need to set up environment secrets, you can do so by following the guide [here](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository). The variables for which you can set secrets are (refer to `.env.template` for default values): - - `VITE_ALGOD_TOKEN` - (This is optional if you are using a public gateway like AlgoNode) - - `VITE_INDEXER_TOKEN` - (This is optional if you are using a public gateway like AlgoNode) - -> If you prefer alternative deployment methods, you can remove the relevant workflow files from the [`.github/workflows`](./.github/workflows) folder and configure your own. +For Vercel: +1. Retrieve your [Vercel Access Token](https://vercel.com/support/articles/how-do-i-use-a-vercel-api-access-token) +2. Install the [Vercel CLI](https://vercel.com/cli) and run `vercel login` +3. Inside your folder, run `vercel link` to create a new Vercel project +4. Inside the generated `.vercel` folder, save the `projectId` and `orgId` from the `project.json` +5. Inside GitHub, add `VERCEL_TOKEN`, `VERCEL_ORG_ID`, and `VERCEL_PROJECT_ID` as [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +6. Create an .env file containing ENV vars for the project (pointing to testnet or mainnet), drag and drop the .env file to upload initial batch of default environment variables to your vercel project. +7. Upon invocation, CD pipeline will pull the VITE_ prefixed environment variables, build the project and deploy to the specified environment. + +For Netlify: +1. Retrieve your [Netlify Access Token](https://docs.netlify.com/cli/get-started/#obtain-a-token-in-the-netlify-ui) +2. Inside your folder run `netlify login` +3. Inside your folder run `netlify sites:create` to create a new site, obtain NETLIFY_SITE_ID from the output +4. Inside GitHub, add `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` as [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +5. Define the VITE_ prefixed environment variables in netlify environment variables under site settings. +6. Upon invocation, CD pipeline will build the project and deploy to the specified environment. + +> If you prefer alternative deployment methods, you can modify the relevant workflow files from the [`.github/workflows`](./.github/workflows) folder or modify deploy scripts in `.algokit.toml`. # Algorand Wallet integrations diff --git a/examples/cloud_provider/production_react_vercel/package.json b/examples/cloud_provider/production_react_vercel/package.json index 414d582..8b529ed 100644 --- a/examples/cloud_provider/production_react_vercel/package.json +++ b/examples/cloud_provider/production_react_vercel/package.json @@ -46,12 +46,16 @@ "tslib": "^2.6.2" }, "scripts": { - "dev": "vite", - "build": "tsc && vite build", + "generate:app-clients": "algokit project link --all", + "dev": "npm run generate:app-clients && vite", + "build": "npm run generate:app-clients && tsc && vite build", "test": "jest --coverage --passWithNoTests", "playwright:test": "playwright test", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:fix": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --fix", + "ci:vercel:build": "vercel build --prod --token=$VERCEL_TOKEN", + "ci:vercel:pull": "vercel pull --yes --environment=production --token=$VERCEL_TOKEN", + "ci:vercel:deploy": "npm run ci:vercel:build && vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN", "preview": "vite preview" }, "eslintConfig": { diff --git a/examples/cloud_provider/production_react_vercel/src/contracts/README.md b/examples/cloud_provider/production_react_vercel/src/contracts/README.md index e056b58..04629b1 100644 --- a/examples/cloud_provider/production_react_vercel/src/contracts/README.md +++ b/examples/cloud_provider/production_react_vercel/src/contracts/README.md @@ -4,10 +4,11 @@ The following folder is reserved for the Algorand Application Clients. The clien To integrate this react frontend template with your smart contracts codebase, perform the following steps: -1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` +1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` or using the dedicated `link` command `algokit project link` (ensure to invoke it from the root of this react project). Using the `link` command is especially useful within workspaces that have multiple contract projects. 2. The generated typescript client should be ready to be imported and used in this react frontend template, making it a full fledged dApp. -### FAQ +> Please note, by default this template defines `"generate:app-clients": "algokit project link --all"` which is a shortcut to automatically link TEAL code from all `contract` projects in the workspace as typed clients into the `frontend` project that is invoking the `link` command. Refer to [documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/project/link.md) to read more about `link` command. -- **How to interact with the smart contract?** - - The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. +## **How to interact with the smart contract?** + +The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. diff --git a/examples/cloud_providers/.gitkeep b/examples/cloud_providers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/examples/cloud_providers/production_react_netlify/.algokit.toml b/examples/cloud_providers/production_react_netlify/.algokit.toml deleted file mode 100644 index 754e2a4..0000000 --- a/examples/cloud_providers/production_react_netlify/.algokit.toml +++ /dev/null @@ -1,10 +0,0 @@ -[algokit] -min_version = "v1.3.0b1" - -[generate.import_contract] -description = "Import a typed client from your smart contracts project" -path = ".algokit/generators/import_contract" - -[project] -type = "frontend" -name = "production_react_netlify" diff --git a/examples/cloud_providers/production_react_netlify/.copier-answers.yml b/examples/cloud_providers/production_react_netlify/.copier-answers.yml deleted file mode 100644 index a2b69a7..0000000 --- a/examples/cloud_providers/production_react_netlify/.copier-answers.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY -_commit: -_src_path: -author_email: None -author_name: None -preset_name: production -project_name: production_react_netlify - diff --git a/examples/cloud_providers/production_react_netlify/.editorconfig b/examples/cloud_providers/production_react_netlify/.editorconfig deleted file mode 100644 index a83b72c..0000000 --- a/examples/cloud_providers/production_react_netlify/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -[*] -charset = utf-8 -insert_final_newline = true -end_of_line = lf -indent_style = space -indent_size = 2 -tab_width = 2 -max_line_length = 140 -trim_trailing_whitespace = true diff --git a/examples/cloud_providers/production_react_netlify/.env.template b/examples/cloud_providers/production_react_netlify/.env.template deleted file mode 100644 index e05d499..0000000 --- a/examples/cloud_providers/production_react_netlify/.env.template +++ /dev/null @@ -1,67 +0,0 @@ -# ====================== -# LocalNet configuration -# uncomment below to use -# ====================== - -VITE_ENVIRONMENT=local - -# Algod -VITE_ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -VITE_ALGOD_SERVER=http://localhost -VITE_ALGOD_PORT=4001 -VITE_ALGOD_NETWORK="" - -# Indexer -VITE_INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -VITE_INDEXER_SERVER=http://localhost -VITE_INDEXER_PORT=8980 - -# KMD -# Please note: -# 1. This is only needed for LocalNet since -# by default KMD provider is ignored on other networks. -# 2. AlgoKit LocalNet starts with a single wallet called 'unencrypted-default-wallet', -# with heaps of tokens available for testing. -VITE_KMD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -VITE_KMD_SERVER=http://localhost -VITE_KMD_PORT=4002 -VITE_KMD_WALLET="unencrypted-default-wallet" -VITE_KMD_PASSWORD="" - -# # ====================== -# # TestNet configuration: -# # uncomment below to use -# # ====================== - -# VITE_ENVIRONMENT=local - -# # Algod -# VITE_ALGOD_TOKEN="" -# VITE_ALGOD_SERVER="https://testnet-api.algonode.cloud" -# VITE_ALGOD_PORT="" -# VITE_ALGOD_NETWORK="testnet" - -# # Indexer -# VITE_INDEXER_TOKEN="" -# VITE_INDEXER_SERVER="https://testnet-idx.algonode.cloud" -# VITE_INDEXER_PORT="" - - -# # ====================== -# # MainNet configuration: -# # uncomment below to use -# # ====================== - -# VITE_ENVIRONMENT=production - -# # Algod -# VITE_ALGOD_TOKEN="" -# VITE_ALGOD_SERVER="https://mainnet-api.algonode.cloud" -# VITE_ALGOD_PORT="" -# VITE_ALGOD_NETWORK="mainnet" - -# # Indexer -# VITE_INDEXER_TOKEN="" -# VITE_INDEXER_SERVER="https://mainnet-idx.algonode.cloud" -# VITE_INDEXER_PORT="" - diff --git a/examples/cloud_providers/production_react_netlify/.eslintrc b/examples/cloud_providers/production_react_netlify/.eslintrc deleted file mode 100644 index 868fe37..0000000 --- a/examples/cloud_providers/production_react_netlify/.eslintrc +++ /dev/null @@ -1,27 +0,0 @@ -{ - "root": true, - "env": { - "node": true - }, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "prettier"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended" - ], - "rules": { - "prettier/prettier": "warn", - "no-console": "warn", - "@typescript-eslint/no-unused-vars": [ - "warn", - { - "ignoreRestSiblings": true, - "argsIgnorePattern": "^_", - "destructuredArrayIgnorePattern": "^_" - } - ], - "prefer-template": "error" - } -} diff --git a/examples/cloud_providers/production_react_netlify/.gitattributes b/examples/cloud_providers/production_react_netlify/.gitattributes deleted file mode 100644 index 6313b56..0000000 --- a/examples/cloud_providers/production_react_netlify/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto eol=lf diff --git a/examples/cloud_providers/production_react_netlify/.github/workflows/checks.yaml b/examples/cloud_providers/production_react_netlify/.github/workflows/checks.yaml deleted file mode 100644 index 41e6fcd..0000000 --- a/examples/cloud_providers/production_react_netlify/.github/workflows/checks.yaml +++ /dev/null @@ -1,54 +0,0 @@ -name: Check code base - -on: - workflow_call: - inputs: - run-build: - required: false - type: boolean - default: false - push: - branches: - - main - -jobs: - checks: - runs-on: 'ubuntu-latest' - steps: - - name: Check out repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Install dependencies - run: npm ci - - - name: Run linters - run: npm run lint - - - name: Run unit tests - run: npm run test - - - name: Create placeholder .env file - if: ${{ inputs.run-build }} - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build - if: ${{ inputs.run-build }} - run: npm run build - - - name: Archive - if: ${{ inputs.run-build }} - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ diff --git a/examples/cloud_providers/production_react_netlify/.github/workflows/pr.yaml b/examples/cloud_providers/production_react_netlify/.github/workflows/pr.yaml deleted file mode 100644 index a80f784..0000000 --- a/examples/cloud_providers/production_react_netlify/.github/workflows/pr.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Pull Request validation - -on: [pull_request] - -jobs: - pr-check: - name: Perform Checks - uses: ./.github/workflows/checks.yaml diff --git a/examples/cloud_providers/production_react_netlify/.github/workflows/release.yaml b/examples/cloud_providers/production_react_netlify/.github/workflows/release.yaml deleted file mode 100644 index ffff1bf..0000000 --- a/examples/cloud_providers/production_react_netlify/.github/workflows/release.yaml +++ /dev/null @@ -1,65 +0,0 @@ -name: Release - -on: - push: - branches: - - main - paths-ignore: - - "docs/**" - - "**.md" - - ".vscode/**" - - ".idea/**" - -permissions: - contents: read - packages: read - -jobs: - lint-and-build: - name: CI dApp - uses: ./.github/workflows/checks.yaml - with: - run-build: true - - - deploy: - runs-on: ubuntu-latest - name: Deploy to Netlify - environment: Prod - concurrency: "${{ github.workflow }}-prod" - needs: - - lint-and-build - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: dist - path: dist - - - name: Replace template vars - uses: makerxstudio/shared-config/.github/actions/placeholder-transforms@main - with: - app-artifact-path: './dist' - static-site-transforms: |- - VITE_ALGOD_TOKEN:${{ secrets.VITE_ALGOD_TOKEN }} - VITE_ALGOD_SERVER:${{ vars.VITE_ALGOD_SERVER }} - VITE_ALGOD_PORT:${{ vars.VITE_ALGOD_PORT }} - VITE_ALGOD_NETWORK:${{ vars.VITE_ALGOD_NETWORK }} - VITE_INDEXER_SERVER:${{ vars.VITE_INDEXER_SERVER }} - VITE_INDEXER_PORT:${{ vars.VITE_INDEXER_PORT }} - VITE_INDEXER_TOKEN:${{ secrets.VITE_INDEXER_TOKEN }} - VITE_ENVIRONMENT:${{ vars.VITE_ENVIRONMENT }} - - - name: Install netlify cli - run: npm i netlify-cli - - - name: Publish to netlify - run: netlify deploy --prod --dir "dist" - env: - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - # Set your netlify project env variables on your github repository (see README for more info) - diff --git a/examples/cloud_providers/production_react_netlify/.gitignore b/examples/cloud_providers/production_react_netlify/.gitignore deleted file mode 100644 index 26dc019..0000000 --- a/examples/cloud_providers/production_react_netlify/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - - -# dotenv environment variable files -.env -env/ - -# misc -/dist -.DS_Store - - -npm-debug.log* -yarn-debug.log* -yarn-error.log* -/test-results/ -/playwright-report/ -/playwright/.cache/ - -# PyCharm -.idea -!.idea/ -.idea/* -!.idea/runConfigurations/ diff --git a/examples/cloud_providers/production_react_netlify/.idea/runConfigurations/Run_Chrome.xml b/examples/cloud_providers/production_react_netlify/.idea/runConfigurations/Run_Chrome.xml deleted file mode 100644 index 9dfeeca..0000000 --- a/examples/cloud_providers/production_react_netlify/.idea/runConfigurations/Run_Chrome.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/examples/cloud_providers/production_react_netlify/.idea/runConfigurations/Run_dApp.xml b/examples/cloud_providers/production_react_netlify/.idea/runConfigurations/Run_dApp.xml deleted file mode 100644 index 1cf2273..0000000 --- a/examples/cloud_providers/production_react_netlify/.idea/runConfigurations/Run_dApp.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - diff --git a/examples/cloud_providers/production_react_netlify/jest.config.ts b/examples/cloud_providers/production_react_netlify/jest.config.ts deleted file mode 100644 index 28a8c3d..0000000 --- a/examples/cloud_providers/production_react_netlify/jest.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Config } from '@jest/types' - -const config: Config.InitialOptions = { - preset: 'ts-jest', - testEnvironment: 'node', - testMatch: ['**/*.spec.ts', '**/*.spec.tsx'], - moduleDirectories: ['node_modules', 'src'], - transform: { - '': [ - 'ts-jest', - { - tsconfig: 'tsconfig.test.json', - }, - ], - }, - coveragePathIgnorePatterns: ['tests'], - testPathIgnorePatterns: ['/tests/'], - } - -export default config diff --git a/examples/cloud_providers/production_react_netlify/package.json b/examples/cloud_providers/production_react_netlify/package.json deleted file mode 100644 index 217bd77..0000000 --- a/examples/cloud_providers/production_react_netlify/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "production_react_netlify", - "version": "0.1.0", - "author": { - "name": "None", - "email": "None" - }, - "private": true, - "type": "module", - "engines": { - "node": ">=18.0" - }, - "devDependencies": { - "@types/node": "^18.17.14", - "@types/react": "^18.2.11", - "@types/react-dom": "^18.2.4", - "@vitejs/plugin-react": "^4.2.1", - "autoprefixer": "^10.4.14", - "eslint": "^8.42.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^5.0.0", - "@typescript-eslint/eslint-plugin": "^6.5.0", - "@typescript-eslint/parser": "^6.5.0", - "postcss": "^8.4.24", - "tailwindcss": "3.3.2", - "ts-jest": "^29.1.1", - "@types/jest": "29.5.2", - "ts-node": "^10.9.1", - "typescript": "^5.1.6", - "@playwright/test": "^1.35.0", - "playwright": "^1.35.0", - "vite": "^5.0.0" - }, - "dependencies": { - "@walletconnect/modal-sign-html": "^2.6.1", - "@algorandfoundation/algokit-utils": "^5.0.0", - "@blockshake/defly-connect": "^1.1.6", - "@daffiwallet/connect": "^1.0.3", - "@perawallet/connect": "^1.3.1", - "@txnlab/use-wallet": "^2.4.0", - "algosdk": "^2.7.0", - "daisyui": "^4.0.0", - "notistack": "^3.0.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "tslib": "^2.6.2" - }, - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "test": "jest --coverage --passWithNoTests", - "playwright:test": "playwright test", - "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "lint:fix": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --fix", - "preview": "vite preview" - }, - "eslintConfig": { - "extends": [ - "react-app/jest", - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/examples/cloud_providers/production_react_netlify/playwright.config.ts b/examples/cloud_providers/production_react_netlify/playwright.config.ts deleted file mode 100644 index d7cbca6..0000000 --- a/examples/cloud_providers/production_react_netlify/playwright.config.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { defineConfig, devices } from '@playwright/test' - -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// require('dotenv').config(); - -/** - * See https://playwright.dev/docs/test-configuration. - */ -export default defineConfig({ - testDir: './tests', - /* Run tests in files in parallel */ - fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'html', - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://127.0.0.1:3000', - - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - testIdAttribute: 'data-test-id', - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - }, - - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ..devices['Desktop Chrome'], channel: 'chrome' }, - // }, - ], - - /* Run your local dev server before starting the tests */ - webServer: { - command: 'npm run dev', - url: 'http://localhost:5173', - reuseExistingServer: !process.env.CI, - }, -}) diff --git a/examples/cloud_providers/production_react_netlify/postcss.config.cjs b/examples/cloud_providers/production_react_netlify/postcss.config.cjs deleted file mode 100644 index 33ad091..0000000 --- a/examples/cloud_providers/production_react_netlify/postcss.config.cjs +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/examples/cloud_providers/production_react_netlify/public/index.html b/examples/cloud_providers/production_react_netlify/public/index.html deleted file mode 100644 index 0d3a3a5..0000000 --- a/examples/cloud_providers/production_react_netlify/public/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - React App - - - -
- - - diff --git a/examples/cloud_providers/production_react_netlify/public/robots.txt b/examples/cloud_providers/production_react_netlify/public/robots.txt deleted file mode 100644 index e9e57dc..0000000 --- a/examples/cloud_providers/production_react_netlify/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/examples/cloud_providers/production_react_netlify/src/App.tsx b/examples/cloud_providers/production_react_netlify/src/App.tsx deleted file mode 100644 index 58feddf..0000000 --- a/examples/cloud_providers/production_react_netlify/src/App.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { DeflyWalletConnect } from '@blockshake/defly-connect' -import { DaffiWalletConnect } from '@daffiwallet/connect' -import { PeraWalletConnect } from '@perawallet/connect' -import { PROVIDER_ID, ProvidersArray, WalletProvider, useInitializeProviders } from '@txnlab/use-wallet' -import algosdk from 'algosdk' -import { SnackbarProvider } from 'notistack' -import Home from './Home' -import { getAlgodConfigFromViteEnvironment, getKmdConfigFromViteEnvironment } from './utils/network/getAlgoClientConfigs' - -let providersArray: ProvidersArray -if (import.meta.env.VITE_ALGOD_NETWORK === '') { - const kmdConfig = getKmdConfigFromViteEnvironment() - providersArray = [ - { - id: PROVIDER_ID.KMD, - clientOptions: { - wallet: kmdConfig.wallet, - password: kmdConfig.password, - host: kmdConfig.server, - token: String(kmdConfig.token), - port: String(kmdConfig.port), - }, - }, - ] -} else { - providersArray = [ - { id: PROVIDER_ID.DEFLY, clientStatic: DeflyWalletConnect }, - { id: PROVIDER_ID.PERA, clientStatic: PeraWalletConnect }, - { id: PROVIDER_ID.DAFFI, clientStatic: DaffiWalletConnect }, - { id: PROVIDER_ID.EXODUS }, - // If you are interested in WalletConnect v2 provider - // refer to https://github.com/TxnLab/use-wallet for detailed integration instructions - ] -} - -export default function App() { - const algodConfig = getAlgodConfigFromViteEnvironment() - - const walletProviders = useInitializeProviders({ - providers: providersArray, - nodeConfig: { - network: algodConfig.network, - nodeServer: algodConfig.server, - nodePort: String(algodConfig.port), - nodeToken: String(algodConfig.token), - }, - algosdkStatic: algosdk, - }) - - return ( - - - - - - ) -} diff --git a/examples/cloud_providers/production_react_netlify/src/Home.tsx b/examples/cloud_providers/production_react_netlify/src/Home.tsx deleted file mode 100644 index 42128d8..0000000 --- a/examples/cloud_providers/production_react_netlify/src/Home.tsx +++ /dev/null @@ -1,63 +0,0 @@ -// src/components/Home.tsx -import { useWallet } from '@txnlab/use-wallet' -import React, { useState } from 'react' -import ConnectWallet from './components/ConnectWallet' -import Transact from './components/Transact' - -interface HomeProps {} - -const Home: React.FC = () => { - const [openWalletModal, setOpenWalletModal] = useState(false) - const [openDemoModal, setOpenDemoModal] = useState(false) - const { activeAddress } = useWallet() - - const toggleWalletModal = () => { - setOpenWalletModal(!openWalletModal) - } - - const toggleDemoModal = () => { - setOpenDemoModal(!openDemoModal) - } - - return ( -
-
-
-

- Welcome to
AlgoKit 🙂
-

-

- This starter has been generated using official AlgoKit React template. Refer to the resource below for next steps. -

- -
- - Getting started - - -
- - - {activeAddress && ( - - )} -
- - - -
-
-
- ) -} - -export default Home diff --git a/examples/cloud_providers/production_react_netlify/src/assets/logo.svg b/examples/cloud_providers/production_react_netlify/src/assets/logo.svg deleted file mode 100644 index 7169476..0000000 --- a/examples/cloud_providers/production_react_netlify/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/cloud_providers/production_react_netlify/src/components/Account.tsx b/examples/cloud_providers/production_react_netlify/src/components/Account.tsx deleted file mode 100644 index 6a6345e..0000000 --- a/examples/cloud_providers/production_react_netlify/src/components/Account.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useWallet } from '@txnlab/use-wallet' -import { useMemo } from 'react' -import { ellipseAddress } from '../utils/ellipseAddress' -import { getAlgodConfigFromViteEnvironment } from '../utils/network/getAlgoClientConfigs' - -const Account = () => { - const { activeAddress } = useWallet() - const algoConfig = getAlgodConfigFromViteEnvironment() - - const dappFlowNetworkName = useMemo(() => { - return algoConfig.network === '' ? 'sandbox' : algoConfig.network.toLocaleLowerCase() - }, [algoConfig.network]) - - return ( -
- - Address: {ellipseAddress(activeAddress)} - -
Network: {algoConfig.network === '' ? 'localnet' : algoConfig.network}
-
- ) -} - -export default Account diff --git a/examples/cloud_providers/production_react_netlify/src/components/ConnectWallet.tsx b/examples/cloud_providers/production_react_netlify/src/components/ConnectWallet.tsx deleted file mode 100644 index c4225bc..0000000 --- a/examples/cloud_providers/production_react_netlify/src/components/ConnectWallet.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Provider, useWallet } from '@txnlab/use-wallet' -import Account from './Account' - -interface ConnectWalletInterface { - openModal: boolean - closeModal: () => void -} - -const ConnectWallet = ({ openModal, closeModal }: ConnectWalletInterface) => { - const { providers, activeAddress } = useWallet() - - const isKmd = (provider: Provider) => provider.metadata.name.toLowerCase() === 'kmd' - - return ( - -
-

Select wallet provider

- -
- {activeAddress && ( - <> - -
- - )} - - {!activeAddress && - providers?.map((provider) => ( - - ))} -
- -
- - {activeAddress && ( - - )} -
- -
- ) -} -export default ConnectWallet diff --git a/examples/cloud_providers/production_react_netlify/src/components/ErrorBoundary.tsx b/examples/cloud_providers/production_react_netlify/src/components/ErrorBoundary.tsx deleted file mode 100644 index 435bf61..0000000 --- a/examples/cloud_providers/production_react_netlify/src/components/ErrorBoundary.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React, { ReactNode } from 'react' - -interface ErrorBoundaryProps { - children: ReactNode -} - -interface ErrorBoundaryState { - hasError: boolean - error: Error | null -} - -class ErrorBoundary extends React.Component { - constructor(props: ErrorBoundaryProps) { - super(props) - this.state = { hasError: false, error: null } - } - - static getDerivedStateFromError(error: Error): ErrorBoundaryState { - // Update state so the next render will show the fallback UI. - return { hasError: true, error: error } - } - - render(): ReactNode { - if (this.state.hasError) { - // You can render any custom fallback UI - return ( -
-
-
-

Error occured

-

- {this.state.error?.message.includes('Attempt to get default algod configuration') - ? 'Please make sure to set up your environment variables correctly. Create a .env file based on .env.template and fill in the required values. This controls the network and credentials for connections with Algod and Indexer.' - : this.state.error?.message} -

-
-
-
- ) - } - - return this.props.children - } -} - -export default ErrorBoundary diff --git a/examples/cloud_providers/production_react_netlify/src/components/Transact.tsx b/examples/cloud_providers/production_react_netlify/src/components/Transact.tsx deleted file mode 100644 index 16bd932..0000000 --- a/examples/cloud_providers/production_react_netlify/src/components/Transact.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import * as algokit from '@algorandfoundation/algokit-utils' -import { useWallet } from '@txnlab/use-wallet' -import algosdk from 'algosdk' -import { useSnackbar } from 'notistack' -import { useState } from 'react' -import { getAlgodConfigFromViteEnvironment } from '../utils/network/getAlgoClientConfigs' - -interface TransactInterface { - openModal: boolean - setModalState: (value: boolean) => void -} - -const Transact = ({ openModal, setModalState }: TransactInterface) => { - const [loading, setLoading] = useState(false) - const [receiverAddress, setReceiverAddress] = useState('') - - const algodConfig = getAlgodConfigFromViteEnvironment() - const algodClient = algokit.getAlgoClient({ - server: algodConfig.server, - port: algodConfig.port, - token: algodConfig.token, - }) - - const { enqueueSnackbar } = useSnackbar() - - const { signer, activeAddress, signTransactions, sendTransactions } = useWallet() - - const handleSubmitAlgo = async () => { - setLoading(true) - - if (!signer || !activeAddress) { - enqueueSnackbar('Please connect wallet first', { variant: 'warning' }) - return - } - - const suggestedParams = await algodClient.getTransactionParams().do() - - const transaction = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: receiverAddress, - amount: 1e6, - suggestedParams, - }) - - const encodedTransaction = algosdk.encodeUnsignedTransaction(transaction) - - const signedTransactions = await signTransactions([encodedTransaction]) - - const waitRoundsToConfirm = 4 - - try { - enqueueSnackbar('Sending transaction...', { variant: 'info' }) - const { id } = await sendTransactions(signedTransactions, waitRoundsToConfirm) - enqueueSnackbar(`Transaction sent: ${id}`, { variant: 'success' }) - setReceiverAddress('') - } catch (e) { - enqueueSnackbar('Failed to send transaction', { variant: 'error' }) - } - - setLoading(false) - } - - return ( - -
-

Send payment transaction

-
- { - setReceiverAddress(e.target.value) - }} - /> -
- - -
-
-
- ) -} - -export default Transact diff --git a/examples/cloud_providers/production_react_netlify/src/contracts/README.md b/examples/cloud_providers/production_react_netlify/src/contracts/README.md deleted file mode 100644 index e056b58..0000000 --- a/examples/cloud_providers/production_react_netlify/src/contracts/README.md +++ /dev/null @@ -1,13 +0,0 @@ -## How to connect my web app with Algorand smart contracts? - -The following folder is reserved for the Algorand Application Clients. The clients are used to interact with instances of Algorand Smart Contracts (ASC1s) deployed on-chain. - -To integrate this react frontend template with your smart contracts codebase, perform the following steps: - -1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` -2. The generated typescript client should be ready to be imported and used in this react frontend template, making it a full fledged dApp. - -### FAQ - -- **How to interact with the smart contract?** - - The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. diff --git a/examples/cloud_providers/production_react_netlify/src/interfaces/network.ts b/examples/cloud_providers/production_react_netlify/src/interfaces/network.ts deleted file mode 100644 index a458edc..0000000 --- a/examples/cloud_providers/production_react_netlify/src/interfaces/network.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { AlgoClientConfig } from '@algorandfoundation/algokit-utils/types/network-client' -import type { TokenHeader } from 'algosdk/dist/types/client/urlTokenBaseHTTPClient' - -export interface AlgoViteClientConfig extends AlgoClientConfig { - /** Base URL of the server e.g. http://localhost, https://testnet-api.algonode.cloud/, etc. */ - server: string - /** The port to use e.g. 4001, 443, etc. */ - port: string | number - /** The token to use for API authentication (or undefined if none needed) - can be a string, or an object with the header key => value */ - token: string | TokenHeader - /** String representing current Algorand Network type (testnet/mainnet and etc) */ - network: string -} - -export interface AlgoViteKMDConfig extends AlgoClientConfig { - /** Base URL of the server e.g. http://localhost, https://testnet-api.algonode.cloud/, etc. */ - server: string - /** The port to use e.g. 4001, 443, etc. */ - port: string | number - /** The token to use for API authentication (or undefined if none needed) - can be a string, or an object with the header key => value */ - token: string | TokenHeader - /** KMD wallet name */ - wallet: string - /** KMD wallet password */ - password: string -} diff --git a/examples/cloud_providers/production_react_netlify/src/main.tsx b/examples/cloud_providers/production_react_netlify/src/main.tsx deleted file mode 100644 index adf72ec..0000000 --- a/examples/cloud_providers/production_react_netlify/src/main.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App' -import './styles/main.css' -import ErrorBoundary from './components/ErrorBoundary' - -ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - - - - - , -) diff --git a/examples/cloud_providers/production_react_netlify/src/styles/main.css b/examples/cloud_providers/production_react_netlify/src/styles/main.css deleted file mode 100644 index b5c61c9..0000000 --- a/examples/cloud_providers/production_react_netlify/src/styles/main.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/examples/cloud_providers/production_react_netlify/src/utils/ellipseAddress.spec.tsx b/examples/cloud_providers/production_react_netlify/src/utils/ellipseAddress.spec.tsx deleted file mode 100644 index 2cbff10..0000000 --- a/examples/cloud_providers/production_react_netlify/src/utils/ellipseAddress.spec.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { ellipseAddress } from './ellipseAddress' - -describe('ellipseAddress', () => { - it('should return ellipsed address with specified width', () => { - const address = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - const result = ellipseAddress(address, 4) - expect(result).toBe('aaaa...aaaa') - }) - - it('should return empty string when address is empty', () => { - const address = '' - const result = ellipseAddress(address) - expect(result).toBe('') - }) -}) diff --git a/examples/cloud_providers/production_react_netlify/src/utils/ellipseAddress.ts b/examples/cloud_providers/production_react_netlify/src/utils/ellipseAddress.ts deleted file mode 100644 index 542f46f..0000000 --- a/examples/cloud_providers/production_react_netlify/src/utils/ellipseAddress.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function ellipseAddress(address = ``, width = 6): string { - return address ? `${address.slice(0, width)}...${address.slice(-width)}` : address -} diff --git a/examples/cloud_providers/production_react_netlify/src/utils/network/getAlgoClientConfigs.ts b/examples/cloud_providers/production_react_netlify/src/utils/network/getAlgoClientConfigs.ts deleted file mode 100644 index b5121f8..0000000 --- a/examples/cloud_providers/production_react_netlify/src/utils/network/getAlgoClientConfigs.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { AlgoViteClientConfig, AlgoViteKMDConfig } from '../../interfaces/network' - -export function getAlgodConfigFromViteEnvironment(): AlgoViteClientConfig { - if (!import.meta.env.VITE_ALGOD_SERVER) { - throw new Error('Attempt to get default algod configuration without specifying VITE_ALGOD_SERVER in the environment variables') - } - - return { - server: import.meta.env.VITE_ALGOD_SERVER, - port: import.meta.env.VITE_ALGOD_PORT, - token: import.meta.env.VITE_ALGOD_TOKEN, - network: import.meta.env.VITE_ALGOD_NETWORK, - } -} - -export function getIndexerConfigFromViteEnvironment(): AlgoViteClientConfig { - if (!import.meta.env.VITE_INDEXER_SERVER) { - throw new Error('Attempt to get default algod configuration without specifying VITE_INDEXER_SERVER in the environment variables') - } - - return { - server: import.meta.env.VITE_INDEXER_SERVER, - port: import.meta.env.VITE_INDEXER_PORT, - token: import.meta.env.VITE_INDEXER_TOKEN, - network: import.meta.env.VITE_ALGOD_NETWORK, - } -} - -export function getKmdConfigFromViteEnvironment(): AlgoViteKMDConfig { - if (!import.meta.env.VITE_KMD_SERVER) { - throw new Error('Attempt to get default kmd configuration without specifying VITE_KMD_SERVER in the environment variables') - } - - return { - server: import.meta.env.VITE_KMD_SERVER, - port: import.meta.env.VITE_KMD_PORT, - token: import.meta.env.VITE_KMD_TOKEN, - wallet: import.meta.env.VITE_KMD_WALLET, - password: import.meta.env.VITE_KMD_PASSWORD, - } -} diff --git a/examples/cloud_providers/production_react_netlify/src/vite-env.d.ts b/examples/cloud_providers/production_react_netlify/src/vite-env.d.ts deleted file mode 100644 index 67c2d30..0000000 --- a/examples/cloud_providers/production_react_netlify/src/vite-env.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -/// - -interface ImportMetaEnv { - readonly VITE_ENVIRONMENT: string - - readonly VITE_ALGOD_TOKEN: string - readonly VITE_ALGOD_SERVER: string - readonly VITE_ALGOD_PORT: string - readonly VITE_ALGOD_NETWORK: string - - readonly VITE_INDEXER_TOKEN: string - readonly VITE_INDEXER_SERVER: string - readonly VITE_INDEXER_PORT: string - - readonly VITE_KMD_TOKEN: string - readonly VITE_KMD_SERVER: string - readonly VITE_KMD_PORT: string - readonly VITE_KMD_PASSWORD: string - readonly VITE_KMD_WALLET: string -} - -interface ImportMeta { - readonly env: ImportMetaEnv -} diff --git a/examples/cloud_providers/production_react_netlify/tailwind.config.js b/examples/cloud_providers/production_react_netlify/tailwind.config.js deleted file mode 100644 index a9f7a95..0000000 --- a/examples/cloud_providers/production_react_netlify/tailwind.config.js +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ['./src/**/*.{js,ts,jsx,tsx}'], - theme: { - extend: {}, - }, - daisyui: { - themes: ['lofi'], - }, - plugins: [require('daisyui')], - } diff --git a/examples/cloud_providers/production_react_netlify/tests/example.spec.ts b/examples/cloud_providers/production_react_netlify/tests/example.spec.ts deleted file mode 100644 index df83322..0000000 --- a/examples/cloud_providers/production_react_netlify/tests/example.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { randomAccount } from '@algorandfoundation/algokit-utils' -import { expect, test } from '@playwright/test' - -test.beforeEach(async ({ page }) => { - await page.goto('http://localhost:5173/') -}) - -test('has title', async ({ page }) => { - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle('AlgoKit React Template') -}) - -test('get started link', async ({ page }) => { - await expect(page.getByTestId('getting-started')).toHaveText('Getting started') -}) - -test('authentication and dummy payment transaction', async ({ page }) => { - page.on('dialog', async (dialog) => { - dialog.message() === 'KMD password' ? await dialog.accept() : await dialog.dismiss() - }) - - // 1. Must be able to connect to a KMD wallet provider - await page.getByTestId('connect-wallet').click() - await page.getByTestId('kmd-connect').click() - await page.getByTestId('close-wallet-modal').click() - - // 2. Must be able to send a dummy payment transaction - await page.getByTestId('transactions-demo').click() - - const dummyAccount = randomAccount() - await page.getByTestId('receiver-address').fill(dummyAccount.addr) - await page.getByTestId('send-algo').click() - - // 3. Must be able to see a notification that the transaction was sent - const notification = await page.getByText('Transaction sent:') - await notification.waitFor() - expect(notification).toBeTruthy() -}) diff --git a/examples/cloud_providers/production_react_netlify/tsconfig.json b/examples/cloud_providers/production_react_netlify/tsconfig.json deleted file mode 100644 index 5cde02a..0000000 --- a/examples/cloud_providers/production_react_netlify/tsconfig.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, - "module": "ES2022" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "declaration": true /* Generates corresponding '.d.ts' file. */, - "declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */, - "sourceMap": true /* Generates corresponding '.map' file. */, - "strict": true /* Enable all strict type-checking options. */, - "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, - "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, - "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, - "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, - "skipLibCheck": true /* Skip type checking of declaration files. */, - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "allowJs": false, - "allowSyntheticDefaultImports": true, - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "outDir": "./dist/" - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx", - "vite.config.js", - "src/utils/ellipseAddress.spec.tsx", - "src/utils/ellipseAddress.spec.tsx", - "src/main.tsx", - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/examples/cloud_providers/production_react_netlify/tsconfig.node.json b/examples/cloud_providers/production_react_netlify/tsconfig.node.json deleted file mode 100644 index 9d31e2a..0000000 --- a/examples/cloud_providers/production_react_netlify/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/examples/cloud_providers/production_react_netlify/vite.config.ts b/examples/cloud_providers/production_react_netlify/vite.config.ts deleted file mode 100644 index 36f7f4e..0000000 --- a/examples/cloud_providers/production_react_netlify/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import react from '@vitejs/plugin-react' -import { defineConfig } from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], -}) diff --git a/examples/cloud_providers/production_react_vercel/.algokit.toml b/examples/cloud_providers/production_react_vercel/.algokit.toml deleted file mode 100644 index f3abe6e..0000000 --- a/examples/cloud_providers/production_react_vercel/.algokit.toml +++ /dev/null @@ -1,10 +0,0 @@ -[algokit] -min_version = "v1.3.0b1" - -[generate.import_contract] -description = "Import a typed client from your smart contracts project" -path = ".algokit/generators/import_contract" - -[project] -type = "frontend" -name = "production_react_vercel" diff --git a/examples/cloud_providers/production_react_vercel/.copier-answers.yml b/examples/cloud_providers/production_react_vercel/.copier-answers.yml deleted file mode 100644 index e4d6d29..0000000 --- a/examples/cloud_providers/production_react_vercel/.copier-answers.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY -_commit: -_src_path: -author_email: None -author_name: None -preset_name: production -project_name: production_react_vercel - diff --git a/examples/cloud_providers/production_react_vercel/.editorconfig b/examples/cloud_providers/production_react_vercel/.editorconfig deleted file mode 100644 index a83b72c..0000000 --- a/examples/cloud_providers/production_react_vercel/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -[*] -charset = utf-8 -insert_final_newline = true -end_of_line = lf -indent_style = space -indent_size = 2 -tab_width = 2 -max_line_length = 140 -trim_trailing_whitespace = true diff --git a/examples/cloud_providers/production_react_vercel/.env.template b/examples/cloud_providers/production_react_vercel/.env.template deleted file mode 100644 index e05d499..0000000 --- a/examples/cloud_providers/production_react_vercel/.env.template +++ /dev/null @@ -1,67 +0,0 @@ -# ====================== -# LocalNet configuration -# uncomment below to use -# ====================== - -VITE_ENVIRONMENT=local - -# Algod -VITE_ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -VITE_ALGOD_SERVER=http://localhost -VITE_ALGOD_PORT=4001 -VITE_ALGOD_NETWORK="" - -# Indexer -VITE_INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -VITE_INDEXER_SERVER=http://localhost -VITE_INDEXER_PORT=8980 - -# KMD -# Please note: -# 1. This is only needed for LocalNet since -# by default KMD provider is ignored on other networks. -# 2. AlgoKit LocalNet starts with a single wallet called 'unencrypted-default-wallet', -# with heaps of tokens available for testing. -VITE_KMD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -VITE_KMD_SERVER=http://localhost -VITE_KMD_PORT=4002 -VITE_KMD_WALLET="unencrypted-default-wallet" -VITE_KMD_PASSWORD="" - -# # ====================== -# # TestNet configuration: -# # uncomment below to use -# # ====================== - -# VITE_ENVIRONMENT=local - -# # Algod -# VITE_ALGOD_TOKEN="" -# VITE_ALGOD_SERVER="https://testnet-api.algonode.cloud" -# VITE_ALGOD_PORT="" -# VITE_ALGOD_NETWORK="testnet" - -# # Indexer -# VITE_INDEXER_TOKEN="" -# VITE_INDEXER_SERVER="https://testnet-idx.algonode.cloud" -# VITE_INDEXER_PORT="" - - -# # ====================== -# # MainNet configuration: -# # uncomment below to use -# # ====================== - -# VITE_ENVIRONMENT=production - -# # Algod -# VITE_ALGOD_TOKEN="" -# VITE_ALGOD_SERVER="https://mainnet-api.algonode.cloud" -# VITE_ALGOD_PORT="" -# VITE_ALGOD_NETWORK="mainnet" - -# # Indexer -# VITE_INDEXER_TOKEN="" -# VITE_INDEXER_SERVER="https://mainnet-idx.algonode.cloud" -# VITE_INDEXER_PORT="" - diff --git a/examples/cloud_providers/production_react_vercel/.eslintrc b/examples/cloud_providers/production_react_vercel/.eslintrc deleted file mode 100644 index 868fe37..0000000 --- a/examples/cloud_providers/production_react_vercel/.eslintrc +++ /dev/null @@ -1,27 +0,0 @@ -{ - "root": true, - "env": { - "node": true - }, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "prettier"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended" - ], - "rules": { - "prettier/prettier": "warn", - "no-console": "warn", - "@typescript-eslint/no-unused-vars": [ - "warn", - { - "ignoreRestSiblings": true, - "argsIgnorePattern": "^_", - "destructuredArrayIgnorePattern": "^_" - } - ], - "prefer-template": "error" - } -} diff --git a/examples/cloud_providers/production_react_vercel/.gitattributes b/examples/cloud_providers/production_react_vercel/.gitattributes deleted file mode 100644 index 6313b56..0000000 --- a/examples/cloud_providers/production_react_vercel/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto eol=lf diff --git a/examples/cloud_providers/production_react_vercel/.github/workflows/checks.yaml b/examples/cloud_providers/production_react_vercel/.github/workflows/checks.yaml deleted file mode 100644 index 41e6fcd..0000000 --- a/examples/cloud_providers/production_react_vercel/.github/workflows/checks.yaml +++ /dev/null @@ -1,54 +0,0 @@ -name: Check code base - -on: - workflow_call: - inputs: - run-build: - required: false - type: boolean - default: false - push: - branches: - - main - -jobs: - checks: - runs-on: 'ubuntu-latest' - steps: - - name: Check out repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Install dependencies - run: npm ci - - - name: Run linters - run: npm run lint - - - name: Run unit tests - run: npm run test - - - name: Create placeholder .env file - if: ${{ inputs.run-build }} - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build - if: ${{ inputs.run-build }} - run: npm run build - - - name: Archive - if: ${{ inputs.run-build }} - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ diff --git a/examples/cloud_providers/production_react_vercel/.github/workflows/pr.yaml b/examples/cloud_providers/production_react_vercel/.github/workflows/pr.yaml deleted file mode 100644 index a80f784..0000000 --- a/examples/cloud_providers/production_react_vercel/.github/workflows/pr.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Pull Request validation - -on: [pull_request] - -jobs: - pr-check: - name: Perform Checks - uses: ./.github/workflows/checks.yaml diff --git a/examples/cloud_providers/production_react_vercel/.github/workflows/release.yaml b/examples/cloud_providers/production_react_vercel/.github/workflows/release.yaml deleted file mode 100644 index 13152f1..0000000 --- a/examples/cloud_providers/production_react_vercel/.github/workflows/release.yaml +++ /dev/null @@ -1,66 +0,0 @@ -name: Release - -on: - push: - branches: - - main - paths-ignore: - - "docs/**" - - "**.md" - - ".vscode/**" - - ".idea/**" - -permissions: - contents: read - packages: read - -jobs: - lint-and-build: - name: CI dApp - uses: ./.github/workflows/checks.yaml - - deploy: - runs-on: ubuntu-latest - name: Deploy to Vercel - environment: Prod - concurrency: "${{ github.workflow }}-prod" - needs: - - lint-and-build - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Install Vercel CLI - run: npm install --global vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - - name: Create placeholder .env file - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - - name: Replace template vars - uses: makerxstudio/shared-config/.github/actions/placeholder-transforms@main - with: - app-artifact-path: './.vercel/output' - static-site-transforms: |- - VITE_ALGOD_TOKEN:${{ secrets.VITE_ALGOD_TOKEN }} - VITE_ALGOD_SERVER:${{ vars.VITE_ALGOD_SERVER }} - VITE_ALGOD_PORT:${{ vars.VITE_ALGOD_PORT }} - VITE_ALGOD_NETWORK:${{ vars.VITE_ALGOD_NETWORK }} - VITE_INDEXER_SERVER:${{ vars.VITE_INDEXER_SERVER }} - VITE_INDEXER_PORT:${{ vars.VITE_INDEXER_PORT }} - VITE_INDEXER_TOKEN:${{ secrets.VITE_INDEXER_TOKEN }} - VITE_ENVIRONMENT:${{ vars.VITE_ENVIRONMENT }} - - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} - # Set your vercel project env variables on your github repository (see README for more info) - diff --git a/examples/cloud_providers/production_react_vercel/.gitignore b/examples/cloud_providers/production_react_vercel/.gitignore deleted file mode 100644 index 26dc019..0000000 --- a/examples/cloud_providers/production_react_vercel/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - - -# dotenv environment variable files -.env -env/ - -# misc -/dist -.DS_Store - - -npm-debug.log* -yarn-debug.log* -yarn-error.log* -/test-results/ -/playwright-report/ -/playwright/.cache/ - -# PyCharm -.idea -!.idea/ -.idea/* -!.idea/runConfigurations/ diff --git a/examples/cloud_providers/production_react_vercel/.idea/runConfigurations/Run_Chrome.xml b/examples/cloud_providers/production_react_vercel/.idea/runConfigurations/Run_Chrome.xml deleted file mode 100644 index 9dfeeca..0000000 --- a/examples/cloud_providers/production_react_vercel/.idea/runConfigurations/Run_Chrome.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/examples/cloud_providers/production_react_vercel/.idea/runConfigurations/Run_dApp.xml b/examples/cloud_providers/production_react_vercel/.idea/runConfigurations/Run_dApp.xml deleted file mode 100644 index 1cf2273..0000000 --- a/examples/cloud_providers/production_react_vercel/.idea/runConfigurations/Run_dApp.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - diff --git a/examples/cloud_providers/production_react_vercel/jest.config.ts b/examples/cloud_providers/production_react_vercel/jest.config.ts deleted file mode 100644 index 28a8c3d..0000000 --- a/examples/cloud_providers/production_react_vercel/jest.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Config } from '@jest/types' - -const config: Config.InitialOptions = { - preset: 'ts-jest', - testEnvironment: 'node', - testMatch: ['**/*.spec.ts', '**/*.spec.tsx'], - moduleDirectories: ['node_modules', 'src'], - transform: { - '': [ - 'ts-jest', - { - tsconfig: 'tsconfig.test.json', - }, - ], - }, - coveragePathIgnorePatterns: ['tests'], - testPathIgnorePatterns: ['/tests/'], - } - -export default config diff --git a/examples/cloud_providers/production_react_vercel/package.json b/examples/cloud_providers/production_react_vercel/package.json deleted file mode 100644 index 414d582..0000000 --- a/examples/cloud_providers/production_react_vercel/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "production_react_vercel", - "version": "0.1.0", - "author": { - "name": "None", - "email": "None" - }, - "private": true, - "type": "module", - "engines": { - "node": ">=18.0" - }, - "devDependencies": { - "@types/node": "^18.17.14", - "@types/react": "^18.2.11", - "@types/react-dom": "^18.2.4", - "@vitejs/plugin-react": "^4.2.1", - "autoprefixer": "^10.4.14", - "eslint": "^8.42.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^5.0.0", - "@typescript-eslint/eslint-plugin": "^6.5.0", - "@typescript-eslint/parser": "^6.5.0", - "postcss": "^8.4.24", - "tailwindcss": "3.3.2", - "ts-jest": "^29.1.1", - "@types/jest": "29.5.2", - "ts-node": "^10.9.1", - "typescript": "^5.1.6", - "@playwright/test": "^1.35.0", - "playwright": "^1.35.0", - "vite": "^5.0.0" - }, - "dependencies": { - "@walletconnect/modal-sign-html": "^2.6.1", - "@algorandfoundation/algokit-utils": "^5.0.0", - "@blockshake/defly-connect": "^1.1.6", - "@daffiwallet/connect": "^1.0.3", - "@perawallet/connect": "^1.3.1", - "@txnlab/use-wallet": "^2.4.0", - "algosdk": "^2.7.0", - "daisyui": "^4.0.0", - "notistack": "^3.0.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "tslib": "^2.6.2" - }, - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "test": "jest --coverage --passWithNoTests", - "playwright:test": "playwright test", - "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "lint:fix": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --fix", - "preview": "vite preview" - }, - "eslintConfig": { - "extends": [ - "react-app/jest", - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/examples/cloud_providers/production_react_vercel/playwright.config.ts b/examples/cloud_providers/production_react_vercel/playwright.config.ts deleted file mode 100644 index d7cbca6..0000000 --- a/examples/cloud_providers/production_react_vercel/playwright.config.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { defineConfig, devices } from '@playwright/test' - -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// require('dotenv').config(); - -/** - * See https://playwright.dev/docs/test-configuration. - */ -export default defineConfig({ - testDir: './tests', - /* Run tests in files in parallel */ - fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'html', - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://127.0.0.1:3000', - - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - testIdAttribute: 'data-test-id', - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - }, - - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ..devices['Desktop Chrome'], channel: 'chrome' }, - // }, - ], - - /* Run your local dev server before starting the tests */ - webServer: { - command: 'npm run dev', - url: 'http://localhost:5173', - reuseExistingServer: !process.env.CI, - }, -}) diff --git a/examples/cloud_providers/production_react_vercel/postcss.config.cjs b/examples/cloud_providers/production_react_vercel/postcss.config.cjs deleted file mode 100644 index 33ad091..0000000 --- a/examples/cloud_providers/production_react_vercel/postcss.config.cjs +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/examples/cloud_providers/production_react_vercel/public/index.html b/examples/cloud_providers/production_react_vercel/public/index.html deleted file mode 100644 index 0d3a3a5..0000000 --- a/examples/cloud_providers/production_react_vercel/public/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - React App - - - -
- - - diff --git a/examples/cloud_providers/production_react_vercel/public/robots.txt b/examples/cloud_providers/production_react_vercel/public/robots.txt deleted file mode 100644 index e9e57dc..0000000 --- a/examples/cloud_providers/production_react_vercel/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/examples/cloud_providers/production_react_vercel/src/App.tsx b/examples/cloud_providers/production_react_vercel/src/App.tsx deleted file mode 100644 index 58feddf..0000000 --- a/examples/cloud_providers/production_react_vercel/src/App.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { DeflyWalletConnect } from '@blockshake/defly-connect' -import { DaffiWalletConnect } from '@daffiwallet/connect' -import { PeraWalletConnect } from '@perawallet/connect' -import { PROVIDER_ID, ProvidersArray, WalletProvider, useInitializeProviders } from '@txnlab/use-wallet' -import algosdk from 'algosdk' -import { SnackbarProvider } from 'notistack' -import Home from './Home' -import { getAlgodConfigFromViteEnvironment, getKmdConfigFromViteEnvironment } from './utils/network/getAlgoClientConfigs' - -let providersArray: ProvidersArray -if (import.meta.env.VITE_ALGOD_NETWORK === '') { - const kmdConfig = getKmdConfigFromViteEnvironment() - providersArray = [ - { - id: PROVIDER_ID.KMD, - clientOptions: { - wallet: kmdConfig.wallet, - password: kmdConfig.password, - host: kmdConfig.server, - token: String(kmdConfig.token), - port: String(kmdConfig.port), - }, - }, - ] -} else { - providersArray = [ - { id: PROVIDER_ID.DEFLY, clientStatic: DeflyWalletConnect }, - { id: PROVIDER_ID.PERA, clientStatic: PeraWalletConnect }, - { id: PROVIDER_ID.DAFFI, clientStatic: DaffiWalletConnect }, - { id: PROVIDER_ID.EXODUS }, - // If you are interested in WalletConnect v2 provider - // refer to https://github.com/TxnLab/use-wallet for detailed integration instructions - ] -} - -export default function App() { - const algodConfig = getAlgodConfigFromViteEnvironment() - - const walletProviders = useInitializeProviders({ - providers: providersArray, - nodeConfig: { - network: algodConfig.network, - nodeServer: algodConfig.server, - nodePort: String(algodConfig.port), - nodeToken: String(algodConfig.token), - }, - algosdkStatic: algosdk, - }) - - return ( - - - - - - ) -} diff --git a/examples/cloud_providers/production_react_vercel/src/Home.tsx b/examples/cloud_providers/production_react_vercel/src/Home.tsx deleted file mode 100644 index 42128d8..0000000 --- a/examples/cloud_providers/production_react_vercel/src/Home.tsx +++ /dev/null @@ -1,63 +0,0 @@ -// src/components/Home.tsx -import { useWallet } from '@txnlab/use-wallet' -import React, { useState } from 'react' -import ConnectWallet from './components/ConnectWallet' -import Transact from './components/Transact' - -interface HomeProps {} - -const Home: React.FC = () => { - const [openWalletModal, setOpenWalletModal] = useState(false) - const [openDemoModal, setOpenDemoModal] = useState(false) - const { activeAddress } = useWallet() - - const toggleWalletModal = () => { - setOpenWalletModal(!openWalletModal) - } - - const toggleDemoModal = () => { - setOpenDemoModal(!openDemoModal) - } - - return ( -
-
-
-

- Welcome to
AlgoKit 🙂
-

-

- This starter has been generated using official AlgoKit React template. Refer to the resource below for next steps. -

- -
- - Getting started - - -
- - - {activeAddress && ( - - )} -
- - - -
-
-
- ) -} - -export default Home diff --git a/examples/cloud_providers/production_react_vercel/src/assets/logo.svg b/examples/cloud_providers/production_react_vercel/src/assets/logo.svg deleted file mode 100644 index 7169476..0000000 --- a/examples/cloud_providers/production_react_vercel/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/cloud_providers/production_react_vercel/src/components/Account.tsx b/examples/cloud_providers/production_react_vercel/src/components/Account.tsx deleted file mode 100644 index 6a6345e..0000000 --- a/examples/cloud_providers/production_react_vercel/src/components/Account.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useWallet } from '@txnlab/use-wallet' -import { useMemo } from 'react' -import { ellipseAddress } from '../utils/ellipseAddress' -import { getAlgodConfigFromViteEnvironment } from '../utils/network/getAlgoClientConfigs' - -const Account = () => { - const { activeAddress } = useWallet() - const algoConfig = getAlgodConfigFromViteEnvironment() - - const dappFlowNetworkName = useMemo(() => { - return algoConfig.network === '' ? 'sandbox' : algoConfig.network.toLocaleLowerCase() - }, [algoConfig.network]) - - return ( -
- - Address: {ellipseAddress(activeAddress)} - -
Network: {algoConfig.network === '' ? 'localnet' : algoConfig.network}
-
- ) -} - -export default Account diff --git a/examples/cloud_providers/production_react_vercel/src/components/ConnectWallet.tsx b/examples/cloud_providers/production_react_vercel/src/components/ConnectWallet.tsx deleted file mode 100644 index c4225bc..0000000 --- a/examples/cloud_providers/production_react_vercel/src/components/ConnectWallet.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Provider, useWallet } from '@txnlab/use-wallet' -import Account from './Account' - -interface ConnectWalletInterface { - openModal: boolean - closeModal: () => void -} - -const ConnectWallet = ({ openModal, closeModal }: ConnectWalletInterface) => { - const { providers, activeAddress } = useWallet() - - const isKmd = (provider: Provider) => provider.metadata.name.toLowerCase() === 'kmd' - - return ( - -
-

Select wallet provider

- -
- {activeAddress && ( - <> - -
- - )} - - {!activeAddress && - providers?.map((provider) => ( - - ))} -
- -
- - {activeAddress && ( - - )} -
- -
- ) -} -export default ConnectWallet diff --git a/examples/cloud_providers/production_react_vercel/src/components/ErrorBoundary.tsx b/examples/cloud_providers/production_react_vercel/src/components/ErrorBoundary.tsx deleted file mode 100644 index 435bf61..0000000 --- a/examples/cloud_providers/production_react_vercel/src/components/ErrorBoundary.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React, { ReactNode } from 'react' - -interface ErrorBoundaryProps { - children: ReactNode -} - -interface ErrorBoundaryState { - hasError: boolean - error: Error | null -} - -class ErrorBoundary extends React.Component { - constructor(props: ErrorBoundaryProps) { - super(props) - this.state = { hasError: false, error: null } - } - - static getDerivedStateFromError(error: Error): ErrorBoundaryState { - // Update state so the next render will show the fallback UI. - return { hasError: true, error: error } - } - - render(): ReactNode { - if (this.state.hasError) { - // You can render any custom fallback UI - return ( -
-
-
-

Error occured

-

- {this.state.error?.message.includes('Attempt to get default algod configuration') - ? 'Please make sure to set up your environment variables correctly. Create a .env file based on .env.template and fill in the required values. This controls the network and credentials for connections with Algod and Indexer.' - : this.state.error?.message} -

-
-
-
- ) - } - - return this.props.children - } -} - -export default ErrorBoundary diff --git a/examples/cloud_providers/production_react_vercel/src/components/Transact.tsx b/examples/cloud_providers/production_react_vercel/src/components/Transact.tsx deleted file mode 100644 index 16bd932..0000000 --- a/examples/cloud_providers/production_react_vercel/src/components/Transact.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import * as algokit from '@algorandfoundation/algokit-utils' -import { useWallet } from '@txnlab/use-wallet' -import algosdk from 'algosdk' -import { useSnackbar } from 'notistack' -import { useState } from 'react' -import { getAlgodConfigFromViteEnvironment } from '../utils/network/getAlgoClientConfigs' - -interface TransactInterface { - openModal: boolean - setModalState: (value: boolean) => void -} - -const Transact = ({ openModal, setModalState }: TransactInterface) => { - const [loading, setLoading] = useState(false) - const [receiverAddress, setReceiverAddress] = useState('') - - const algodConfig = getAlgodConfigFromViteEnvironment() - const algodClient = algokit.getAlgoClient({ - server: algodConfig.server, - port: algodConfig.port, - token: algodConfig.token, - }) - - const { enqueueSnackbar } = useSnackbar() - - const { signer, activeAddress, signTransactions, sendTransactions } = useWallet() - - const handleSubmitAlgo = async () => { - setLoading(true) - - if (!signer || !activeAddress) { - enqueueSnackbar('Please connect wallet first', { variant: 'warning' }) - return - } - - const suggestedParams = await algodClient.getTransactionParams().do() - - const transaction = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: receiverAddress, - amount: 1e6, - suggestedParams, - }) - - const encodedTransaction = algosdk.encodeUnsignedTransaction(transaction) - - const signedTransactions = await signTransactions([encodedTransaction]) - - const waitRoundsToConfirm = 4 - - try { - enqueueSnackbar('Sending transaction...', { variant: 'info' }) - const { id } = await sendTransactions(signedTransactions, waitRoundsToConfirm) - enqueueSnackbar(`Transaction sent: ${id}`, { variant: 'success' }) - setReceiverAddress('') - } catch (e) { - enqueueSnackbar('Failed to send transaction', { variant: 'error' }) - } - - setLoading(false) - } - - return ( - -
-

Send payment transaction

-
- { - setReceiverAddress(e.target.value) - }} - /> -
- - -
-
-
- ) -} - -export default Transact diff --git a/examples/cloud_providers/production_react_vercel/src/contracts/README.md b/examples/cloud_providers/production_react_vercel/src/contracts/README.md deleted file mode 100644 index e056b58..0000000 --- a/examples/cloud_providers/production_react_vercel/src/contracts/README.md +++ /dev/null @@ -1,13 +0,0 @@ -## How to connect my web app with Algorand smart contracts? - -The following folder is reserved for the Algorand Application Clients. The clients are used to interact with instances of Algorand Smart Contracts (ASC1s) deployed on-chain. - -To integrate this react frontend template with your smart contracts codebase, perform the following steps: - -1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` -2. The generated typescript client should be ready to be imported and used in this react frontend template, making it a full fledged dApp. - -### FAQ - -- **How to interact with the smart contract?** - - The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. diff --git a/examples/cloud_providers/production_react_vercel/src/interfaces/network.ts b/examples/cloud_providers/production_react_vercel/src/interfaces/network.ts deleted file mode 100644 index a458edc..0000000 --- a/examples/cloud_providers/production_react_vercel/src/interfaces/network.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { AlgoClientConfig } from '@algorandfoundation/algokit-utils/types/network-client' -import type { TokenHeader } from 'algosdk/dist/types/client/urlTokenBaseHTTPClient' - -export interface AlgoViteClientConfig extends AlgoClientConfig { - /** Base URL of the server e.g. http://localhost, https://testnet-api.algonode.cloud/, etc. */ - server: string - /** The port to use e.g. 4001, 443, etc. */ - port: string | number - /** The token to use for API authentication (or undefined if none needed) - can be a string, or an object with the header key => value */ - token: string | TokenHeader - /** String representing current Algorand Network type (testnet/mainnet and etc) */ - network: string -} - -export interface AlgoViteKMDConfig extends AlgoClientConfig { - /** Base URL of the server e.g. http://localhost, https://testnet-api.algonode.cloud/, etc. */ - server: string - /** The port to use e.g. 4001, 443, etc. */ - port: string | number - /** The token to use for API authentication (or undefined if none needed) - can be a string, or an object with the header key => value */ - token: string | TokenHeader - /** KMD wallet name */ - wallet: string - /** KMD wallet password */ - password: string -} diff --git a/examples/cloud_providers/production_react_vercel/src/main.tsx b/examples/cloud_providers/production_react_vercel/src/main.tsx deleted file mode 100644 index adf72ec..0000000 --- a/examples/cloud_providers/production_react_vercel/src/main.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App' -import './styles/main.css' -import ErrorBoundary from './components/ErrorBoundary' - -ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - - - - - , -) diff --git a/examples/cloud_providers/production_react_vercel/src/styles/main.css b/examples/cloud_providers/production_react_vercel/src/styles/main.css deleted file mode 100644 index b5c61c9..0000000 --- a/examples/cloud_providers/production_react_vercel/src/styles/main.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/examples/cloud_providers/production_react_vercel/src/utils/ellipseAddress.spec.tsx b/examples/cloud_providers/production_react_vercel/src/utils/ellipseAddress.spec.tsx deleted file mode 100644 index 2cbff10..0000000 --- a/examples/cloud_providers/production_react_vercel/src/utils/ellipseAddress.spec.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { ellipseAddress } from './ellipseAddress' - -describe('ellipseAddress', () => { - it('should return ellipsed address with specified width', () => { - const address = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - const result = ellipseAddress(address, 4) - expect(result).toBe('aaaa...aaaa') - }) - - it('should return empty string when address is empty', () => { - const address = '' - const result = ellipseAddress(address) - expect(result).toBe('') - }) -}) diff --git a/examples/cloud_providers/production_react_vercel/src/utils/ellipseAddress.ts b/examples/cloud_providers/production_react_vercel/src/utils/ellipseAddress.ts deleted file mode 100644 index 542f46f..0000000 --- a/examples/cloud_providers/production_react_vercel/src/utils/ellipseAddress.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function ellipseAddress(address = ``, width = 6): string { - return address ? `${address.slice(0, width)}...${address.slice(-width)}` : address -} diff --git a/examples/cloud_providers/production_react_vercel/src/utils/network/getAlgoClientConfigs.ts b/examples/cloud_providers/production_react_vercel/src/utils/network/getAlgoClientConfigs.ts deleted file mode 100644 index b5121f8..0000000 --- a/examples/cloud_providers/production_react_vercel/src/utils/network/getAlgoClientConfigs.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { AlgoViteClientConfig, AlgoViteKMDConfig } from '../../interfaces/network' - -export function getAlgodConfigFromViteEnvironment(): AlgoViteClientConfig { - if (!import.meta.env.VITE_ALGOD_SERVER) { - throw new Error('Attempt to get default algod configuration without specifying VITE_ALGOD_SERVER in the environment variables') - } - - return { - server: import.meta.env.VITE_ALGOD_SERVER, - port: import.meta.env.VITE_ALGOD_PORT, - token: import.meta.env.VITE_ALGOD_TOKEN, - network: import.meta.env.VITE_ALGOD_NETWORK, - } -} - -export function getIndexerConfigFromViteEnvironment(): AlgoViteClientConfig { - if (!import.meta.env.VITE_INDEXER_SERVER) { - throw new Error('Attempt to get default algod configuration without specifying VITE_INDEXER_SERVER in the environment variables') - } - - return { - server: import.meta.env.VITE_INDEXER_SERVER, - port: import.meta.env.VITE_INDEXER_PORT, - token: import.meta.env.VITE_INDEXER_TOKEN, - network: import.meta.env.VITE_ALGOD_NETWORK, - } -} - -export function getKmdConfigFromViteEnvironment(): AlgoViteKMDConfig { - if (!import.meta.env.VITE_KMD_SERVER) { - throw new Error('Attempt to get default kmd configuration without specifying VITE_KMD_SERVER in the environment variables') - } - - return { - server: import.meta.env.VITE_KMD_SERVER, - port: import.meta.env.VITE_KMD_PORT, - token: import.meta.env.VITE_KMD_TOKEN, - wallet: import.meta.env.VITE_KMD_WALLET, - password: import.meta.env.VITE_KMD_PASSWORD, - } -} diff --git a/examples/cloud_providers/production_react_vercel/src/vite-env.d.ts b/examples/cloud_providers/production_react_vercel/src/vite-env.d.ts deleted file mode 100644 index 67c2d30..0000000 --- a/examples/cloud_providers/production_react_vercel/src/vite-env.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -/// - -interface ImportMetaEnv { - readonly VITE_ENVIRONMENT: string - - readonly VITE_ALGOD_TOKEN: string - readonly VITE_ALGOD_SERVER: string - readonly VITE_ALGOD_PORT: string - readonly VITE_ALGOD_NETWORK: string - - readonly VITE_INDEXER_TOKEN: string - readonly VITE_INDEXER_SERVER: string - readonly VITE_INDEXER_PORT: string - - readonly VITE_KMD_TOKEN: string - readonly VITE_KMD_SERVER: string - readonly VITE_KMD_PORT: string - readonly VITE_KMD_PASSWORD: string - readonly VITE_KMD_WALLET: string -} - -interface ImportMeta { - readonly env: ImportMetaEnv -} diff --git a/examples/cloud_providers/production_react_vercel/tailwind.config.js b/examples/cloud_providers/production_react_vercel/tailwind.config.js deleted file mode 100644 index a9f7a95..0000000 --- a/examples/cloud_providers/production_react_vercel/tailwind.config.js +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ['./src/**/*.{js,ts,jsx,tsx}'], - theme: { - extend: {}, - }, - daisyui: { - themes: ['lofi'], - }, - plugins: [require('daisyui')], - } diff --git a/examples/cloud_providers/production_react_vercel/tests/example.spec.ts b/examples/cloud_providers/production_react_vercel/tests/example.spec.ts deleted file mode 100644 index df83322..0000000 --- a/examples/cloud_providers/production_react_vercel/tests/example.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { randomAccount } from '@algorandfoundation/algokit-utils' -import { expect, test } from '@playwright/test' - -test.beforeEach(async ({ page }) => { - await page.goto('http://localhost:5173/') -}) - -test('has title', async ({ page }) => { - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle('AlgoKit React Template') -}) - -test('get started link', async ({ page }) => { - await expect(page.getByTestId('getting-started')).toHaveText('Getting started') -}) - -test('authentication and dummy payment transaction', async ({ page }) => { - page.on('dialog', async (dialog) => { - dialog.message() === 'KMD password' ? await dialog.accept() : await dialog.dismiss() - }) - - // 1. Must be able to connect to a KMD wallet provider - await page.getByTestId('connect-wallet').click() - await page.getByTestId('kmd-connect').click() - await page.getByTestId('close-wallet-modal').click() - - // 2. Must be able to send a dummy payment transaction - await page.getByTestId('transactions-demo').click() - - const dummyAccount = randomAccount() - await page.getByTestId('receiver-address').fill(dummyAccount.addr) - await page.getByTestId('send-algo').click() - - // 3. Must be able to see a notification that the transaction was sent - const notification = await page.getByText('Transaction sent:') - await notification.waitFor() - expect(notification).toBeTruthy() -}) diff --git a/examples/cloud_providers/production_react_vercel/tsconfig.json b/examples/cloud_providers/production_react_vercel/tsconfig.json deleted file mode 100644 index 5cde02a..0000000 --- a/examples/cloud_providers/production_react_vercel/tsconfig.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, - "module": "ES2022" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "declaration": true /* Generates corresponding '.d.ts' file. */, - "declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */, - "sourceMap": true /* Generates corresponding '.map' file. */, - "strict": true /* Enable all strict type-checking options. */, - "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, - "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, - "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, - "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, - "skipLibCheck": true /* Skip type checking of declaration files. */, - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "allowJs": false, - "allowSyntheticDefaultImports": true, - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "outDir": "./dist/" - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx", - "vite.config.js", - "src/utils/ellipseAddress.spec.tsx", - "src/utils/ellipseAddress.spec.tsx", - "src/main.tsx", - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/examples/cloud_providers/production_react_vercel/tsconfig.node.json b/examples/cloud_providers/production_react_vercel/tsconfig.node.json deleted file mode 100644 index 9d31e2a..0000000 --- a/examples/cloud_providers/production_react_vercel/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/examples/cloud_providers/production_react_vercel/vite.config.ts b/examples/cloud_providers/production_react_vercel/vite.config.ts deleted file mode 100644 index 36f7f4e..0000000 --- a/examples/cloud_providers/production_react_vercel/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import react from '@vitejs/plugin-react' -import { defineConfig } from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], -}) diff --git a/examples/production_react/.algokit.toml b/examples/production_react/.algokit.toml index 197568b..2c0b47b 100644 --- a/examples/production_react/.algokit.toml +++ b/examples/production_react/.algokit.toml @@ -1,5 +1,5 @@ [algokit] -min_version = "v1.3.0b1" +min_version = "v2.0.0" [generate.import_contract] description = "Import a typed client from your smart contracts project" @@ -7,4 +7,10 @@ path = ".algokit/generators/import_contract" [project] type = "frontend" -name = "production_react" +name = 'production_react' +artifacts = "src/contracts" + +[project.run] +build = { commands = ['npm run build'], description = 'Build frontend' } +test = { commands = ['npm run test'], description = 'Run frontend tests' } +lint = { commands = ['npm run lint'], description = 'Lint frontend code' } diff --git a/examples/production_react/.github/workflows/checks.yaml b/examples/production_react/.github/workflows/checks.yaml deleted file mode 100644 index 4723b1a..0000000 --- a/examples/production_react/.github/workflows/checks.yaml +++ /dev/null @@ -1,54 +0,0 @@ -name: Check code base - -on: - workflow_call: - inputs: - run-build: - required: false - type: boolean - default: false - push: - branches: - - main - -jobs: - checks: - runs-on: 'ubuntu-latest' - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Install dependencies - run: npm ci - - - name: Run linters - run: npm run lint - - - name: Run unit tests - run: npm run test - - - name: Create placeholder .env file - if: ${{ inputs.run-build }} - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build - if: ${{ inputs.run-build }} - run: npm run build - - - name: Archive - if: ${{ inputs.run-build }} - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ diff --git a/examples/production_react/.github/workflows/pr.yaml b/examples/production_react/.github/workflows/pr.yaml deleted file mode 100644 index a80f784..0000000 --- a/examples/production_react/.github/workflows/pr.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Pull Request validation - -on: [pull_request] - -jobs: - pr-check: - name: Perform Checks - uses: ./.github/workflows/checks.yaml diff --git a/examples/production_react/.github/workflows/production-react-cd.yaml b/examples/production_react/.github/workflows/production-react-cd.yaml new file mode 100644 index 0000000..ba6e0ee --- /dev/null +++ b/examples/production_react/.github/workflows/production-react-cd.yaml @@ -0,0 +1,44 @@ +name: Release production_react + +on: + workflow_call: + push: + branches: + - main + paths-ignore: + - "docs/**" + - "**.md" + - ".vscode/**" + - ".idea/**" + +permissions: + contents: read + packages: read + +jobs: + validate: + name: Validate production_react + uses: ./.github/workflows/production-react-ci.yaml + deploy: + runs-on: ubuntu-latest + name: Deploy to Netlify + environment: frontend-prod + + needs: + - validate + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install algokit + run: pipx install algokit + + - name: Bootstrap dependencies + run: algokit bootstrap all --project-name 'production_react' + \ No newline at end of file diff --git a/examples/production_react/.github/workflows/production-react-ci.yaml b/examples/production_react/.github/workflows/production-react-ci.yaml new file mode 100644 index 0000000..b88cb23 --- /dev/null +++ b/examples/production_react/.github/workflows/production-react-ci.yaml @@ -0,0 +1,48 @@ +name: Validate production_react + +on: + + workflow_call: + pull_request: + + +jobs: + validate: + runs-on: 'ubuntu-latest' + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install poetry + run: pipx install poetry + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "poetry" + + - name: Install algokit + run: pipx install algokit + + - name: Install dependencies + run: algokit bootstrap all --project-name 'production_react' + + + - name: Run linters + run: algokit project run lint --project-name 'production_react' + + + - name: Run unit tests + run: algokit project run test --project-name 'production_react' + + + - name: Build + run: algokit project run build --project-name 'production_react' diff --git a/examples/production_react/.github/workflows/release.yaml b/examples/production_react/.github/workflows/release.yaml deleted file mode 100644 index b6a5206..0000000 --- a/examples/production_react/.github/workflows/release.yaml +++ /dev/null @@ -1,62 +0,0 @@ -name: Release - -on: - push: - branches: - - main - paths-ignore: - - "docs/**" - - "**.md" - - ".vscode/**" - - ".idea/**" - -permissions: - contents: read - packages: read - -jobs: - lint-and-build: - name: CI dApp - uses: ./.github/workflows/checks.yaml - - deploy: - runs-on: ubuntu-latest - name: Deploy to Netlify - environment: Prod - concurrency: "${{ github.workflow }}-prod" - needs: - - lint-and-build - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: dist - path: dist - - - name: Replace template vars - uses: makerxstudio/shared-config/.github/actions/placeholder-transforms@main - with: - app-artifact-path: './dist' - static-site-transforms: |- - VITE_ALGOD_TOKEN:${{ secrets.VITE_ALGOD_TOKEN }} - VITE_ALGOD_SERVER:${{ vars.VITE_ALGOD_SERVER }} - VITE_ALGOD_PORT:${{ vars.VITE_ALGOD_PORT }} - VITE_ALGOD_NETWORK:${{ vars.VITE_ALGOD_NETWORK }} - VITE_INDEXER_SERVER:${{ vars.VITE_INDEXER_SERVER }} - VITE_INDEXER_PORT:${{ vars.VITE_INDEXER_PORT }} - VITE_INDEXER_TOKEN:${{ secrets.VITE_INDEXER_TOKEN }} - VITE_ENVIRONMENT:${{ vars.VITE_ENVIRONMENT }} - - - name: Install netlify cli - run: npm i netlify-cli - - - name: Publish to netlify - run: netlify deploy --prod --dir "dist" - env: - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - # Set your netlify project env variables on your github repository (see README for more info) - diff --git a/examples/production_react/.gitignore b/examples/production_react/.gitignore index 26dc019..b1ce837 100644 --- a/examples/production_react/.gitignore +++ b/examples/production_react/.gitignore @@ -33,3 +33,6 @@ yarn-error.log* !.idea/ .idea/* !.idea/runConfigurations/ + +.vercel +.netlify diff --git a/examples/production_react/README.md b/examples/production_react/README.md index 2387940..187c719 100644 --- a/examples/production_react/README.md +++ b/examples/production_react/README.md @@ -33,7 +33,7 @@ This starter React project has been generated using AlgoKit. See below for defau ### Continuous Integration -This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI workflows, which are located in the [`.github/workflows`](./.github/workflows) folder. +This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI workflows, which are located in the [.github/workflows](`.github/workflows`) folder. For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions: @@ -41,6 +41,8 @@ For pull requests and pushes to `main` branch against this repository the follow - `lint`: Lints the codebase using `ESLint` - `build`: Builds the codebase using `vite` +> Please note, if you instantiated the project via `algokit init` without explicitly specifying the `--no-workspace` flag, we will automatically attempt to move the contents of the `.github` folder to the root of the workspace. + ### Continuous Deployment The project template provides base Github Actions workflows for continuous deployment to [Netlify](https://www.netlify.com/) or [Vercel](https://vercel.com/). These workflows are located in the [`.github/workflows`](./.github/workflows) folder. @@ -50,20 +52,24 @@ The project template provides base Github Actions workflows for continuous deplo #### Setting up environment variables and secrets for webapp deployment -1. [Create a new environment variable on your repository](https://docs.github.com/en/actions/learn-github-actions/variables#creating-configuration-variables-for-a-repository) called `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` if you are using Netlify as your cloud provider. Set it to the value of your Netlify auth token respectively. You can find your Netlify auth token by going to [app.netlify.com](https://app.netlify.com/). -2. If you are using Vercel as your cloud provider, create a new environment variable on your repository called `VERCEL_TOKEN`. Set it to the value of your Vercel auth token. You can find your Vercel auth token by going to [vercel.com/account/tokens](https://vercel.com/account/tokens). -3. Set up the environment variables. You can refer to the `.env.template` for default values. The variables to be set are: - - `VITE_ALGOD_SERVER` - - `VITE_ALGOD_NETWORK` - - `VITE_INDEXER_SERVER` - - `VITE_ENVIRONMENT` - (Set to either `production` or `development`) - - `VITE_ALGOD_PORT` - (This is optional if you are using a public gateway like AlgoNode) - - `VITE_INDEXER_PORT` - (This is optional if you are using a public gateway like AlgoNode) -4. (Optional) If you need to set up environment secrets, you can do so by following the guide [here](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository). The variables for which you can set secrets are (refer to `.env.template` for default values): - - `VITE_ALGOD_TOKEN` - (This is optional if you are using a public gateway like AlgoNode) - - `VITE_INDEXER_TOKEN` - (This is optional if you are using a public gateway like AlgoNode) - -> If you prefer alternative deployment methods, you can remove the relevant workflow files from the [`.github/workflows`](./.github/workflows) folder and configure your own. +For Vercel: +1. Retrieve your [Vercel Access Token](https://vercel.com/support/articles/how-do-i-use-a-vercel-api-access-token) +2. Install the [Vercel CLI](https://vercel.com/cli) and run `vercel login` +3. Inside your folder, run `vercel link` to create a new Vercel project +4. Inside the generated `.vercel` folder, save the `projectId` and `orgId` from the `project.json` +5. Inside GitHub, add `VERCEL_TOKEN`, `VERCEL_ORG_ID`, and `VERCEL_PROJECT_ID` as [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +6. Create an .env file containing ENV vars for the project (pointing to testnet or mainnet), drag and drop the .env file to upload initial batch of default environment variables to your vercel project. +7. Upon invocation, CD pipeline will pull the VITE_ prefixed environment variables, build the project and deploy to the specified environment. + +For Netlify: +1. Retrieve your [Netlify Access Token](https://docs.netlify.com/cli/get-started/#obtain-a-token-in-the-netlify-ui) +2. Inside your folder run `netlify login` +3. Inside your folder run `netlify sites:create` to create a new site, obtain NETLIFY_SITE_ID from the output +4. Inside GitHub, add `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` as [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +5. Define the VITE_ prefixed environment variables in netlify environment variables under site settings. +6. Upon invocation, CD pipeline will build the project and deploy to the specified environment. + +> If you prefer alternative deployment methods, you can modify the relevant workflow files from the [`.github/workflows`](./.github/workflows) folder or modify deploy scripts in `.algokit.toml`. # Algorand Wallet integrations diff --git a/examples/production_react/package.json b/examples/production_react/package.json index 0cd594b..79ad360 100644 --- a/examples/production_react/package.json +++ b/examples/production_react/package.json @@ -46,8 +46,9 @@ "tslib": "^2.6.2" }, "scripts": { - "dev": "vite", - "build": "tsc && vite build", + "generate:app-clients": "algokit project link --all", + "dev": "npm run generate:app-clients && vite", + "build": "npm run generate:app-clients && tsc && vite build", "test": "jest --coverage --passWithNoTests", "playwright:test": "playwright test", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", diff --git a/examples/production_react/src/contracts/README.md b/examples/production_react/src/contracts/README.md index e056b58..04629b1 100644 --- a/examples/production_react/src/contracts/README.md +++ b/examples/production_react/src/contracts/README.md @@ -4,10 +4,11 @@ The following folder is reserved for the Algorand Application Clients. The clien To integrate this react frontend template with your smart contracts codebase, perform the following steps: -1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` +1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` or using the dedicated `link` command `algokit project link` (ensure to invoke it from the root of this react project). Using the `link` command is especially useful within workspaces that have multiple contract projects. 2. The generated typescript client should be ready to be imported and used in this react frontend template, making it a full fledged dApp. -### FAQ +> Please note, by default this template defines `"generate:app-clients": "algokit project link --all"` which is a shortcut to automatically link TEAL code from all `contract` projects in the workspace as typed clients into the `frontend` project that is invoking the `link` command. Refer to [documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/project/link.md) to read more about `link` command. -- **How to interact with the smart contract?** - - The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. +## **How to interact with the smart contract?** + +The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. diff --git a/examples/starter_react/.algokit.toml b/examples/starter_react/.algokit.toml index 58fbbe7..efcf2a5 100644 --- a/examples/starter_react/.algokit.toml +++ b/examples/starter_react/.algokit.toml @@ -1,5 +1,5 @@ [algokit] -min_version = "v1.3.0b1" +min_version = "v2.0.0" [generate.import_contract] description = "Import a typed client from your smart contracts project" @@ -7,4 +7,9 @@ path = ".algokit/generators/import_contract" [project] type = "frontend" -name = "starter_react" +name = 'starter_react' +artifacts = "src/contracts" + +[project.run] +build = { commands = ['npm run build'], description = 'Build frontend' } +test = { commands = ['npm run test'], description = 'Run frontend tests' } diff --git a/examples/starter_react/.gitignore b/examples/starter_react/.gitignore index 26dc019..b1ce837 100644 --- a/examples/starter_react/.gitignore +++ b/examples/starter_react/.gitignore @@ -33,3 +33,6 @@ yarn-error.log* !.idea/ .idea/* !.idea/runConfigurations/ + +.vercel +.netlify diff --git a/examples/starter_react/package.json b/examples/starter_react/package.json index dc25421..06afb4d 100644 --- a/examples/starter_react/package.json +++ b/examples/starter_react/package.json @@ -34,8 +34,9 @@ "tslib": "^2.6.2" }, "scripts": { - "dev": "vite", - "build": "tsc && vite build", + "generate:app-clients": "algokit project link --all", + "dev": "npm run generate:app-clients && vite", + "build": "npm run generate:app-clients && tsc && vite build", "preview": "vite preview" }, "eslintConfig": { diff --git a/examples/starter_react/src/contracts/README.md b/examples/starter_react/src/contracts/README.md index e056b58..04629b1 100644 --- a/examples/starter_react/src/contracts/README.md +++ b/examples/starter_react/src/contracts/README.md @@ -4,10 +4,11 @@ The following folder is reserved for the Algorand Application Clients. The clien To integrate this react frontend template with your smart contracts codebase, perform the following steps: -1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` +1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` or using the dedicated `link` command `algokit project link` (ensure to invoke it from the root of this react project). Using the `link` command is especially useful within workspaces that have multiple contract projects. 2. The generated typescript client should be ready to be imported and used in this react frontend template, making it a full fledged dApp. -### FAQ +> Please note, by default this template defines `"generate:app-clients": "algokit project link --all"` which is a shortcut to automatically link TEAL code from all `contract` projects in the workspace as typed clients into the `frontend` project that is invoking the `link` command. Refer to [documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/project/link.md) to read more about `link` command. -- **How to interact with the smart contract?** - - The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. +## **How to interact with the smart contract?** + +The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. diff --git a/includes/project_name_kebab.jinja b/includes/project_name_kebab.jinja new file mode 100644 index 0000000..9bd9740 --- /dev/null +++ b/includes/project_name_kebab.jinja @@ -0,0 +1 @@ +{{- project_name | trim | replace("_", "-") | replace(" ", "-") | lower() | regex_replace('[-]+', '-') | regex_replace('[^a-z0-9.-]', '') -}} diff --git a/poetry.lock b/poetry.lock index 1ecebdb..9ab72f8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiohttp" @@ -688,85 +688,101 @@ files = [ [[package]] name = "multidict" -version = "6.0.4" +version = "6.0.5" description = "multidict implementation" optional = false python-versions = ">=3.7" files = [ - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, - {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, - {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, - {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, - {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, - {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, - {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, - {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, - {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, - {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, - {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, - {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, - {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, + {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, + {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, + {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, + {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] [[package]] diff --git a/template_content/.algokit.toml.jinja b/template_content/.algokit.toml.jinja index 41f9604..919f491 100644 --- a/template_content/.algokit.toml.jinja +++ b/template_content/.algokit.toml.jinja @@ -1,5 +1,5 @@ [algokit] -min_version = "v1.3.0b1" +min_version = "v2.0.0" [generate.import_contract] description = "Import a typed client from your smart contracts project" @@ -7,4 +7,26 @@ path = ".algokit/generators/import_contract" [project] type = "frontend" -name = "{{ project_name }}" +name = '{{ project_name }}' +artifacts = "src/contracts" + +[project.run] +build = { commands = ['npm run build'], description = 'Build frontend' } +test = { commands = ['npm run test'], description = 'Run frontend tests' } +{% if use_eslint_prettier -%} +lint = { commands = ['npm run lint'], description = 'Lint frontend code' } +{% endif -%} +{% if cloud_provider == 'vercel' -%} +ci-deploy-vercel = { commands = [ + 'npm install --global vercel@latest', + 'npm run ci:vercel:pull', + 'npm run ci:vercel:deploy', + ], description = 'Deploy to Vercel' } +{% elif cloud_provider == 'netlify' -%} +ci-deploy-netlify = { commands = [ + 'npm install --global netlify-cli@latest', + 'netlify login', + 'netlify deploy --build --prod' + ], description = 'Deploy to Netlify' } +{% endif -%} + diff --git a/template_content/.gitignore b/template_content/.gitignore index 26dc019..b1ce837 100644 --- a/template_content/.gitignore +++ b/template_content/.gitignore @@ -33,3 +33,6 @@ yarn-error.log* !.idea/ .idea/* !.idea/runConfigurations/ + +.vercel +.netlify diff --git a/template_content/README.md.jinja b/template_content/README.md.jinja index db2ce03..9c5faee 100644 --- a/template_content/README.md.jinja +++ b/template_content/README.md.jinja @@ -35,7 +35,7 @@ This starter React project has been generated using AlgoKit. See below for defau ### Continuous Integration -This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI workflows, which are located in the [`.github/workflows`](./.github/workflows) folder. +This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI workflows, which are located in the [.github/workflows](`{% if use_workspace %}../../.github/workflows{% else %}.github/workflows{% endif %}`) folder. For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions: @@ -43,6 +43,8 @@ For pull requests and pushes to `main` branch against this repository the follow - `lint`: Lints the codebase using `ESLint` - `build`: Builds the codebase using `vite` +> Please note, if you instantiated the project via `algokit init` without explicitly specifying the `--no-workspace` flag, we will automatically attempt to move the contents of the `.github` folder to the root of the workspace. + ### Continuous Deployment The project template provides base Github Actions workflows for continuous deployment to [Netlify](https://www.netlify.com/) or [Vercel](https://vercel.com/). These workflows are located in the [`.github/workflows`](./.github/workflows) folder. @@ -52,20 +54,24 @@ The project template provides base Github Actions workflows for continuous deplo {% if cloud_provider != none %} #### Setting up environment variables and secrets for webapp deployment -1. [Create a new environment variable on your repository](https://docs.github.com/en/actions/learn-github-actions/variables#creating-configuration-variables-for-a-repository) called `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` if you are using Netlify as your cloud provider. Set it to the value of your Netlify auth token respectively. You can find your Netlify auth token by going to [app.netlify.com](https://app.netlify.com/). -2. If you are using Vercel as your cloud provider, create a new environment variable on your repository called `VERCEL_TOKEN`. Set it to the value of your Vercel auth token. You can find your Vercel auth token by going to [vercel.com/account/tokens](https://vercel.com/account/tokens). -3. Set up the environment variables. You can refer to the `.env.template` for default values. The variables to be set are: - - `VITE_ALGOD_SERVER` - - `VITE_ALGOD_NETWORK` - - `VITE_INDEXER_SERVER` - - `VITE_ENVIRONMENT` - (Set to either `production` or `development`) - - `VITE_ALGOD_PORT` - (This is optional if you are using a public gateway like AlgoNode) - - `VITE_INDEXER_PORT` - (This is optional if you are using a public gateway like AlgoNode) -4. (Optional) If you need to set up environment secrets, you can do so by following the guide [here](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository). The variables for which you can set secrets are (refer to `.env.template` for default values): - - `VITE_ALGOD_TOKEN` - (This is optional if you are using a public gateway like AlgoNode) - - `VITE_INDEXER_TOKEN` - (This is optional if you are using a public gateway like AlgoNode) - -> If you prefer alternative deployment methods, you can remove the relevant workflow files from the [`.github/workflows`](./.github/workflows) folder and configure your own. +For Vercel: +1. Retrieve your [Vercel Access Token](https://vercel.com/support/articles/how-do-i-use-a-vercel-api-access-token) +2. Install the [Vercel CLI](https://vercel.com/cli) and run `vercel login` +3. Inside your folder, run `vercel link` to create a new Vercel project +4. Inside the generated `.vercel` folder, save the `projectId` and `orgId` from the `project.json` +5. Inside GitHub, add `VERCEL_TOKEN`, `VERCEL_ORG_ID`, and `VERCEL_PROJECT_ID` as [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +6. Create an .env file containing ENV vars for the project (pointing to testnet or mainnet), drag and drop the .env file to upload initial batch of default environment variables to your vercel project. +7. Upon invocation, CD pipeline will pull the VITE_ prefixed environment variables, build the project and deploy to the specified environment. + +For Netlify: +1. Retrieve your [Netlify Access Token](https://docs.netlify.com/cli/get-started/#obtain-a-token-in-the-netlify-ui) +2. Inside your folder run `netlify login` +3. Inside your folder run `netlify sites:create` to create a new site, obtain NETLIFY_SITE_ID from the output +4. Inside GitHub, add `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` as [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +5. Define the VITE_ prefixed environment variables in netlify environment variables under site settings. +6. Upon invocation, CD pipeline will build the project and deploy to the specified environment. + +> If you prefer alternative deployment methods, you can modify the relevant workflow files from the [`.github/workflows`](./.github/workflows) folder or modify deploy scripts in `.algokit.toml`. {% endif %} {% endif -%} diff --git a/template_content/package.json.jinja b/template_content/package.json.jinja index d0d4706..81fa504 100644 --- a/template_content/package.json.jinja +++ b/template_content/package.json.jinja @@ -56,8 +56,9 @@ "tslib": "^2.6.2" }, "scripts": { - "dev": "vite", - "build": "tsc && vite build", + "generate:app-clients": "algokit project link --all", + "dev": "npm run generate:app-clients && vite", + "build": "npm run generate:app-clients && tsc && vite build", {% if use_jest -%} "test": "jest --coverage --passWithNoTests", {% endif -%} @@ -68,6 +69,11 @@ "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:fix": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --fix", {% endif -%} + {% if cloud_provider == 'vercel' -%} + "ci:vercel:build": "vercel build --prod --token=$VERCEL_TOKEN", + "ci:vercel:pull": "vercel pull --yes --environment=production --token=$VERCEL_TOKEN", + "ci:vercel:deploy": "npm run ci:vercel:build && vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN", + {% endif -%} "preview": "vite preview" }, "eslintConfig": { diff --git a/template_content/src/contracts/README.md b/template_content/src/contracts/README.md index e056b58..04629b1 100644 --- a/template_content/src/contracts/README.md +++ b/template_content/src/contracts/README.md @@ -4,10 +4,11 @@ The following folder is reserved for the Algorand Application Clients. The clien To integrate this react frontend template with your smart contracts codebase, perform the following steps: -1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` +1. Generate the typed client using `algokit generate client -l typescript -o {path/to/this/folder}` or using the dedicated `link` command `algokit project link` (ensure to invoke it from the root of this react project). Using the `link` command is especially useful within workspaces that have multiple contract projects. 2. The generated typescript client should be ready to be imported and used in this react frontend template, making it a full fledged dApp. -### FAQ +> Please note, by default this template defines `"generate:app-clients": "algokit project link --all"` which is a shortcut to automatically link TEAL code from all `contract` projects in the workspace as typed clients into the `frontend` project that is invoking the `link` command. Refer to [documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/project/link.md) to read more about `link` command. -- **How to interact with the smart contract?** - - The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. +## **How to interact with the smart contract?** + +The generated client provides a set of functions that can be used to interact with the ABI (Application Binary Interface) compliant Algorand smart contract. For example, if the smart contract has a function called `hello`, the generated client will have a function called `hello` that can be used to interact with the smart contract. Refer to a [full-stack end-to-end starter template](https://github.com/algorandfoundation/algokit-fullstack-template) for a reference example on invoking and interacting with typescript typed clients generated. diff --git a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/checks.yaml.jinja b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/checks.yaml.jinja deleted file mode 100644 index 61aeddf..0000000 --- a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/checks.yaml.jinja +++ /dev/null @@ -1,54 +0,0 @@ -name: Check code base - -on: - workflow_call: - inputs: - run-build: - required: false - type: boolean - default: false - push: - branches: - - main - -jobs: - checks: - runs-on: 'ubuntu-latest' - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Install dependencies - run: npm ci - - - name: Run linters - run: npm run lint - {% if use_jest %} - - name: Run unit tests - run: npm run test - {% endif %} - - name: Create placeholder .env file - if: ${{ '{{' }} inputs.run-build {{ '}}' }} - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build - if: ${{ '{{' }} inputs.run-build {{ '}}' }} - run: npm run build - - - name: Archive - if: ${{ '{{' }} inputs.run-build {{ '}}' }} - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ diff --git a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/pr.yaml b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/pr.yaml deleted file mode 100644 index a80f784..0000000 --- a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/pr.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Pull Request validation - -on: [pull_request] - -jobs: - pr-check: - name: Perform Checks - uses: ./.github/workflows/checks.yaml diff --git a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% if cloud_provider != none %}release.yaml{% endif %}.jinja b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% if cloud_provider != none %}release.yaml{% endif %}.jinja deleted file mode 100644 index 4dad2c5..0000000 --- a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% if cloud_provider != none %}release.yaml{% endif %}.jinja +++ /dev/null @@ -1,105 +0,0 @@ -name: Release - -on: - push: - branches: - - main - paths-ignore: - - "docs/**" - - "**.md" - - ".vscode/**" - - ".idea/**" - -permissions: - contents: read - packages: read - -jobs: - lint-and-build: - name: CI dApp - uses: ./.github/workflows/checks.yaml - {%- if cloud_provider == 'netlify' %} - with: - run-build: true - {% endif %} - - deploy: - runs-on: ubuntu-latest - name: Deploy to {% if cloud_provider == 'vercel' %}Vercel{% else %}Netlify{% endif %} - environment: Prod - concurrency: {% raw %}"${{ github.workflow }}-prod"{% endraw %} - needs: - - lint-and-build - steps: - - name: Checkout code - uses: actions/checkout@v2 - - {%- if cloud_provider == 'vercel' %} - {% raw %} - - name: Install Vercel CLI - run: npm install --global vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - - name: Create placeholder .env file - uses: makerxstudio/shared-config/.github/actions/env-to-placeholders@main - with: - env-output-path: './.env' - env-template-path: './.env.template' - env-variable-prefix: VITE_ - - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - - name: Replace template vars - uses: makerxstudio/shared-config/.github/actions/placeholder-transforms@main - with: - app-artifact-path: './.vercel/output' - static-site-transforms: |- - VITE_ALGOD_TOKEN:${{ secrets.VITE_ALGOD_TOKEN }} - VITE_ALGOD_SERVER:${{ vars.VITE_ALGOD_SERVER }} - VITE_ALGOD_PORT:${{ vars.VITE_ALGOD_PORT }} - VITE_ALGOD_NETWORK:${{ vars.VITE_ALGOD_NETWORK }} - VITE_INDEXER_SERVER:${{ vars.VITE_INDEXER_SERVER }} - VITE_INDEXER_PORT:${{ vars.VITE_INDEXER_PORT }} - VITE_INDEXER_TOKEN:${{ secrets.VITE_INDEXER_TOKEN }} - VITE_ENVIRONMENT:${{ vars.VITE_ENVIRONMENT }} - - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} - # Set your vercel project env variables on your github repository (see README for more info) - {% endraw %} - {%- else %} - {% raw %} - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: dist - path: dist - - - name: Replace template vars - uses: makerxstudio/shared-config/.github/actions/placeholder-transforms@main - with: - app-artifact-path: './dist' - static-site-transforms: |- - VITE_ALGOD_TOKEN:${{ secrets.VITE_ALGOD_TOKEN }} - VITE_ALGOD_SERVER:${{ vars.VITE_ALGOD_SERVER }} - VITE_ALGOD_PORT:${{ vars.VITE_ALGOD_PORT }} - VITE_ALGOD_NETWORK:${{ vars.VITE_ALGOD_NETWORK }} - VITE_INDEXER_SERVER:${{ vars.VITE_INDEXER_SERVER }} - VITE_INDEXER_PORT:${{ vars.VITE_INDEXER_PORT }} - VITE_INDEXER_TOKEN:${{ secrets.VITE_INDEXER_TOKEN }} - VITE_ENVIRONMENT:${{ vars.VITE_ENVIRONMENT }} - - - name: Install netlify cli - run: npm i netlify-cli - - - name: Publish to netlify - run: netlify deploy --prod --dir "dist" - env: - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - # Set your netlify project env variables on your github repository (see README for more info) - {% endraw %} - {%- endif %} diff --git a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% if cloud_provider != none %}{% include pathjoin('includes', 'project_name_kebab.jinja') %}-cd.yaml{% endif %}.jinja b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% if cloud_provider != none %}{% include pathjoin('includes', 'project_name_kebab.jinja') %}-cd.yaml{% endif %}.jinja new file mode 100644 index 0000000..b10eb35 --- /dev/null +++ b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% if cloud_provider != none %}{% include pathjoin('includes', 'project_name_kebab.jinja') %}-cd.yaml{% endif %}.jinja @@ -0,0 +1,69 @@ +name: Release {{ project_name }} + +on: + {% if not use_workspace -%} + workflow_call: + push: + branches: + - main + paths-ignore: + - "docs/**" + - "**.md" + - ".vscode/**" + - ".idea/**" + {% else -%} + workflow_call: + {%- endif %} +permissions: + contents: read + packages: read + +jobs: + {% if not use_workspace -%} + validate: + name: Validate {{ project_name }} + uses: ./.github/workflows/{% include pathjoin('includes', 'project_name_kebab.jinja') %}-ci.yaml + {%- endif %} + deploy: + runs-on: ubuntu-latest + name: Deploy to {% if cloud_provider == 'vercel' %}Vercel{% else %}Netlify{% endif %} + environment: frontend-prod + {% if not use_workspace %} + needs: + - validate + {% endif %} + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install algokit + run: pipx install algokit + + - name: Bootstrap dependencies + run: algokit bootstrap all --project-name '{{ project_name }}' + {% if cloud_provider == 'vercel' %} + - name: Publish to Vercel + env: + VERCEL_TOKEN: ${{ '{{' }} secrets.VERCEL_TOKEN {{ '}}' }} + VERCEL_PROJECT_ID: ${{ '{{' }} secrets.VERCEL_PROJECT_ID {{ '}}' }} + VERCEL_ORG_ID: ${{ '{{' }} secrets.VERCEL_ORG_ID {{ '}}' }} + run: | + npm install --global vercel@canary + vercel pull --yes --environment=production --token=${{ '{{' }} secrets.VERCEL_TOKEN {{ '}}' }} + vercel build --prod + vercel deploy --prebuilt --prod + {% elif cloud_provider == 'netlify' %} + - name: Publish to Netlify + env: + NETLIFY_SITE_ID: ${{ '{{' }} secrets.NETLIFY_SITE_ID {{ '}}' }} + NETLIFY_AUTH_TOKEN: ${{ '{{' }} secrets.NETLIFY_AUTH_TOKEN {{ '}}' }} + run: | + npm install --global netlify-cli@latest + netlify login + netlify deploy --build --prod + {% endif -%} diff --git a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% include pathjoin('includes', 'project_name_kebab.jinja') %}-ci.yaml.jinja b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% include pathjoin('includes', 'project_name_kebab.jinja') %}-ci.yaml.jinja new file mode 100644 index 0000000..05720d3 --- /dev/null +++ b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/{% include pathjoin('includes', 'project_name_kebab.jinja') %}-ci.yaml.jinja @@ -0,0 +1,50 @@ +name: Validate {{ project_name }} + +on: + {% if not use_workspace %} + workflow_call: + pull_request: + {% else %} + workflow_call: + {% endif %} + +jobs: + validate: + runs-on: 'ubuntu-latest' + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install poetry + run: pipx install poetry + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "poetry" + + - name: Install algokit + run: pipx install algokit + + - name: Install dependencies + run: algokit bootstrap all --project-name '{{ project_name }}' + + {% if use_eslint_prettier %} + - name: Run linters + run: algokit project run lint --project-name '{{ project_name }}' + {% endif %} + {% if use_jest %} + - name: Run unit tests + run: algokit project run test --project-name '{{ project_name }}' + {% endif %} + + - name: Build + run: algokit project run build --project-name '{{ project_name }}' diff --git a/tests/test_custom_answers.py b/tests/test_custom_answers.py index 7f60ce6..2bdd812 100644 --- a/tests/test_custom_answers.py +++ b/tests/test_custom_answers.py @@ -16,9 +16,9 @@ generated_root = root / generated_folder config_path = Path(__file__).parent.parent / "pyproject.toml" -NPM_INSTALL_ARGS = ["npm", "install"] -NPM_LINT_ARGS = ["npm", "run", "lint"] -NPM_BUILD_ARGS = ["npm", "run", "build"] +LINT_ARGS = ["algokit", "project", "run", "lint"] +BUILD_ARGS = ["algokit", "project", "run", "build"] +TEST_ARGS = ["algokit", "project", "run", "test"] def _generate_default_parameters( @@ -89,7 +89,6 @@ def run_init( "--defaults", "--no-ide", "--no-git", - "--no-bootstrap", "--no-workspace", ] answers = { @@ -157,13 +156,14 @@ def run_init( # preset tests @pytest.mark.parametrize("cloud_provider", ["vercel", "netlify"]) def test_production_react_cloud(working_dir: Path, cloud_provider: str) -> None: + response = run_init( working_dir, f"production_react_{cloud_provider}", answers=_generate_default_parameters( preset_name="production", cloud_provider=cloud_provider ), - custom_check_args=[NPM_INSTALL_ARGS, NPM_LINT_ARGS, NPM_BUILD_ARGS], + custom_check_args=[BUILD_ARGS, TEST_ARGS, LINT_ARGS], ) assert response.returncode == 0, response.stdout diff --git a/tests/test_templates.py b/tests/test_templates.py index 9a23bf4..a213a1a 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -16,9 +16,9 @@ generated_root = root / generated_folder config_path = Path(__file__).parent.parent / "pyproject.toml" -NPM_INSTALL_ARGS = ["npm", "install"] -NPM_LINT_ARGS = ["npm", "run", "lint"] -NPM_BUILD_ARGS = ["npm", "run", "build"] +LINT_ARGS = ["algokit", "project", "run", "lint"] +BUILD_ARGS = ["algokit", "project", "run", "build"] +TEST_ARGS = ["algokit", "project", "run", "test"] def _generate_default_parameters( @@ -89,7 +89,6 @@ def run_init( "--defaults", "--no-ide", "--no-git", - "--no-bootstrap", "--no-workspace", ] answers = { @@ -155,11 +154,16 @@ def run_init( @pytest.mark.parametrize("preset_name", ["starter", "production"]) def test_react_templates(working_dir: Path, preset_name: str) -> None: + custom_check_args = [BUILD_ARGS] + + if preset_name == "production": + custom_check_args += [TEST_ARGS, LINT_ARGS] + response = run_init( working_dir, f"{preset_name}_react", answers=_generate_default_parameters(preset_name=preset_name), - custom_check_args=[NPM_INSTALL_ARGS, NPM_BUILD_ARGS], + custom_check_args=custom_check_args, ) assert response.returncode == 0, response.stdout