Add formspree and react-admin templates to sites#10031
Conversation
📝 WalkthroughWalkthroughAdds two UseCases constants ( Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
🔇 Additional comments (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
app/config/templates/site.php (3)
1418-1436: Complete the template configuration for Formspree integration.The Formspree template appears incomplete:
- Wrong screenshot URLs: Using lynx gallery template URLs instead of Formspree-specific ones.
- Empty variables array: Formspree typically requires configuration variables (e.g., form endpoint, API key).
- Incomplete TODO items: Multiple TODO comments suggest this template needs further development.
Since this is a WIP template, consider adding typical Formspree environment variables:
- 'variables' => [] // TODO: Add env vars once added to template + 'variables' => [ + [ + 'name' => 'VITE_FORMSPREE_ENDPOINT', + 'description' => 'Your Formspree form endpoint', + 'value' => '', + 'placeholder' => 'https://formspree.io/f/your-form-id', + 'required' => true, + 'type' => 'text' + ], + ]And update the screenshot URLs:
- 'screenshotDark' => $url . '/images/sites/templates/gallery-for-lynx-dark.png', // TODO: Update this - 'screenshotLight' => $url . '/images/sites/templates/gallery-for-lynx-light.png', // TODO: Update this + 'screenshotDark' => $url . '/images/sites/templates/template-for-formspree-dark.png', + 'screenshotLight' => $url . '/images/sites/templates/template-for-formspree-light.png',
1437-1455: Complete the template configuration for Clerk integration.The Clerk template configuration is incomplete:
- Wrong screenshot URLs: Using lynx gallery template URLs instead of Clerk-specific ones.
- Missing environment variables: Clerk integration typically requires API keys and configuration.
- Incomplete TODO items: Multiple TODO comments indicate this template needs completion.
Consider adding typical Clerk environment variables for Next.js:
- 'variables' => [] // TODO: Add the relevant variables for Clerk + 'variables' => [ + [ + 'name' => 'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY', + 'description' => 'Your Clerk publishable key', + 'value' => '', + 'placeholder' => 'pk_test_...', + 'required' => true, + 'type' => 'text' + ], + [ + 'name' => 'CLERK_SECRET_KEY', + 'description' => 'Your Clerk secret key', + 'value' => '', + 'placeholder' => 'sk_test_...', + 'required' => true, + 'type' => 'password' + ], + ]And update the screenshot URLs:
- 'screenshotDark' => $url . '/images/sites/templates/gallery-for-lynx-dark.png', // TODO: Update this - 'screenshotLight' => $url . '/images/sites/templates/gallery-for-lynx-light.png', // TODO: Update this + 'screenshotDark' => $url . '/images/sites/templates/template-for-clerk-dark.png', + 'screenshotLight' => $url . '/images/sites/templates/template-for-clerk-light.png',
1373-1455: Consider the use case categorization for these templates.All three new templates use
UseCases::STARTERwith TODO comments questioning if they need new categories. Consider:
- React Admin Dashboard: Could fit better in a new
ADMINorDASHBOARDcategory- Formspree: Could fit in a
FORMScategory or remain asSTARTER- Clerk: Could fit in an
AUTHcategory or remain asSTARTERThe current categorization works for now, but you might want to evaluate if new use case categories would provide better organization as more specialized templates are added.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/config/templates/site.php(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Linter
- GitHub Check: Check if utopia-php/database changed
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
✨ Benchmark results
⚡ Benchmark Comparison
|
Move disable
|
We need to remove Clerk from here |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
app/config/templates/site.php (1)
1368-1412: Address the TODO comment and consider adjusting the score.The template configuration looks correct, but:
- Line 1373 has a TODO about checking if a new category is needed. Since this is an admin dashboard, consider whether a new use case category (e.g.,
UseCases::ADMINorUseCases::DASHBOARD) would be more appropriate thanSTARTER.- The score is set to 1, which the guidelines suggest avoiding if possible (see line 175 comment).
Do you want me to help create a new use case category or suggest a more appropriate existing category for this admin dashboard template?
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/config/templates/site.php(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
🔇 Additional comments (1)
app/config/templates/site.php (1)
1413-1431: Score of 1 and incomplete configuration are consistent with other new templates in this file.The flagged items match the pattern for recently-added templates:
- Empty
variablesarray aligns with all templates in the file; the TODO indicates it will be completed when the external template repository adds supportUseCases::STARTERis a valid category; the TODO may reflect uncertainty about whether a more specific category applies- Score of 1 is used across multiple templates; the guideline permits it when necessary
No action required—these are intentional work-in-progress markers.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
app/config/templates/site.php (1)
1475-1519: Resolve remaining TODOs and finalize metadata for React Admin template.This entry looks structurally good (paths, screenshots, env vars), but there are still metadata gaps:
- Line 1479:
scoreis set to1, which goes against the inline guidance to avoid 1,2,3,8,9,10 if possible. Consider picking a more representative score.- Line 1480: The
TODOonuseCasessuggests the category is undecided. Before merge, either confirmUseCases::STARTERis correct or update it and remove theTODOso the config is “final”.
🧹 Nitpick comments (1)
app/config/templates/site.php (1)
1521-1538: Finalize Formspree template configuration (score, useCases, env vars).The Formspree entry is valid PHP, but still looks unfinished:
- Line 1524:
scoreis1, conflicting with the “avoid 1,2,3,8,9,10 if possible” guidance; choose a more realistic value once screenshots are final.- Line 1525:
TODOonuseCasesimplies the category isn’t finalized; decide on the correct category and drop theTODO.- Line 1537:
variablesis empty with aTODO. If the template truly needs no env vars, remove the comment; otherwise, add the required keys (e.g., Formspree IDs) so deployments aren’t missing configuration.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/config/templates/site.php(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
|
@Meldiron I see this error when trying to create a new screenshot
@adityaoberai ➜ /workspaces/appwrite (chore-add-new-site-templates) $ docker compose exec appwrite screenshot --templateId="job-applications-formspree"
Found: Job applications form with Formspree
Email: [email protected]
Pass: password
User created
Session created
Team created
Project created
Site created
Variables created
{"headers":{"server":"Appwrite","x-content-type-options":"nosniff","access-control-allow-methods":"GET, POST, PUT, PATCH, DELETE","access-control-allow-headers":"Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Dev-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Forwarded-For, X-Forwarded-User-Agent","access-control-expose-headers":"X-Appwrite-Session, X-Fallback-Cookies","access-control-allow-origin":"http:\/\/localhost","access-control-allow-credentials":"true","x-debug-fallback":"false","cache-control":"no-cache, no-store, must-revalidate","expires":"0","pragma":"no-cache","x-debug-speed":"0.0053830146789551","content-type":"application\/json; charset=UTF-8","date":"Fri, 05 Dec 2025 18:47:02 GMT","connection":"keep-alive","content-length":"2297","status-code":400},"cookies":[],"body":{"message":"Param \"type\" is not optional.","code":400,"type":"general_argument_invalid","version":"1.8.0","file":"\/usr\/src\/code\/vendor\/utopia-php\/framework\/src\/App.php","line":698,"trace":[{"file":"\/usr\/src\/code\/vendor\/utopia-php\/framework\/src\/App.php","line":611,"function":"getArguments","class":"Utopia\\App","type":"->","args":[[],{"siteId":"693328a64fc8d3358c23"},{"owner":"appwrite","repository":"templates-for-sites","rootDirectory":".\/react\/formspree","version":"0.7.*","activate":true}]},{"file":"\/usr\/src\/code\/vendor\/utopia-php\/framework\/src\/App.php","line":831,"function":"execute","class":"Utopia\\App","type":"->","args":[[],[],[]]},{"file":"\/usr\/src\/code\/vendor\/utopia-php\/framework\/src\/App.php","line":728,"function":"runInternal","class":"Utopia\\App","type":"->","args":[[],[]]},{"file":"\/usr\/src\/code\/app\/http.php","line":460,"function":"run","class":"Utopia\\App","type":"->","args":[[],[]]},{"function":"{closure}","args":[{"fd":59,"streamId":0,"header":{"host":"localhost","user-agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.77 Safari\/537.36","accept":"*\/*","content-type":"application\/json","x-sdk-version":"appwrite:php:v1.0.7","origin":"http:\/\/localhost","x-appwrite-project":"693328a56b2d0e722244","x-appwrite-mode":"admin","content-length":"127"},"server":{"request_method":"POST","request_uri":"\/v1\/sites\/693328a64fc8d3358c23\/deployments\/template","path_info":"\/v1\/sites\/693328a64fc8d3358c23\/deployments\/template","request_time":1764960422,"request_time_float":1764960422.385935,"server_protocol":"HTTP\/1.1","server_port":80,"remote_port":44054,"remote_addr":"127.0.0.1","master_time":1764960422},"cookie":{"a_session_console":"eyJpZCI6IjY5MzMyOGE1M2M5ZWRmODk3MGRlIiwic2VjcmV0IjoiMTVlOGM1YmU2YzI0ZDViZThiMjYwYWIwODc1ZTZlZTViZjgwMTEzMzY4MGEwY2IxYmMwNWE4Y2I4NjYwYTI0Nzc0MDUyZTdkNmIwOTY0MDdkYjI5Zjk0NTEwNGI4OTZjZGY3MzQ1MzdhYWQ4NjM1NGVmZmQ0MzNiOTRiYzRlOWU4NTk0YzdjM2E0MDQ3ZDkwNWYxNzk2ZDY2N2YzODlhYmZiN2NjYjY1NGNiNTcxZjg3ZDBlOGRhMWI5YzFmOGRkZGRlOWFlY2IwNzRiYTI2ODYzYzE3NDJmZTMzOWQ3MzE0OGRhOGQ5MDliNDZiMTVhMDg0NTY4M2NmNmM2OGIxNiJ9"},"get":null,"files":null,"post":null,"tmpfiles":null},{"fd":59,"socket":null,"header":null,"cookie":null,"trailer":null}]}]}}
[Error] Timestamp: 2025-12-05T18:47:02+00:00
[Error] Type: Exception
[Error] Message: Failed to create deployment
[Error] File: /usr/src/code/src/Appwrite/Platform/Tasks/Screenshot.php
[Error] Line: 216
[Error] Trace: #0 /usr/src/code/vendor/utopia-php/cli/src/CLI/CLI.php(321): Appwrite\Platform\Tasks\Screenshot->action('job-application...')
#1 [internal function]: Utopia\CLI\CLI->run()
#2 {main}Not sure why this is happening |
There was a problem hiding this comment.
Actionable comments posted: 3
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/config/templates/site.php(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Check if utopia-php/database changed
- GitHub Check: Linter
- GitHub Check: scan
🔇 Additional comments (2)
app/config/templates/site.php (2)
28-29: LGTM!The new use case constants follow the established naming pattern and are appropriately used in the template definitions below.
1580-1607: The template configuration is valid and complete.The
job-applications-formspreetemplate has all required fields correctly defined, including thetypeproperty in the variables array. The configuration follows the standard template pattern and the variableVITE_FORMSPREE_FORM_IDis properly scoped. No issues found with the configuration itself.Note: The screenshot files referenced in the configuration may be generated at deployment time rather than stored in the repository. The error "Param 'type' is not optional" mentioned in the original comment does not apply to this template—it relates to unrelated GraphQL parameter validation.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
src/Appwrite/Platform/Tasks/Screenshot.php (2)
144-147: Consider using a clearer approach to get the last specification.The
\end()function modifies the array's internal pointer as a side effect. While this works, using\array_key_last()would be more explicit and avoid side effects.Apply this diff for improved clarity:
// Use best specifications to prevent out-of-memory during build $specifications = Config::getParam('specifications', []); $specifications = array_keys($specifications); - $specification = \end($specifications); + $specification = \array_key_last($specifications) ? $specifications[\array_key_last($specifications)] : \end($specifications);Or even simpler:
$specifications = Config::getParam('specifications', []); - $specifications = array_keys($specifications); - $specification = \end($specifications); + $specificationKeys = array_keys($specifications); + $specification = \end($specificationKeys);
54-54: Consider adding a clarifying comment for the hardcoded endpoint.The hardcoded
http://localhost/v1is correct for the CLI client running inside the Docker container, while line 208 dynamically constructs theapiEndpointfor deployed sites. Adding a comment would make this distinction clearer for future maintainers.+ // Internal endpoint for CLI client communication (within Docker) $client->setEndpoint('http://localhost/v1');
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
public/images/sites/templates/crm-dashboard-react-admin-dark.pngis excluded by!**/*.pngpublic/images/sites/templates/crm-dashboard-react-admin-light.pngis excluded by!**/*.pngpublic/images/sites/templates/job-applications-formspree-dark.pngis excluded by!**/*.pngpublic/images/sites/templates/job-applications-formspree-light.pngis excluded by!**/*.png
📒 Files selected for processing (1)
src/Appwrite/Platform/Tasks/Screenshot.php(6 hunks)
🧰 Additional context used
🪛 GitHub Actions: Linter
src/Appwrite/Platform/Tasks/Screenshot.php
[error] 1-1: PSR-12: single_space_around_construct issue detected by Pint. Please fix the formatting as per PSR-12 rules.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
🔇 Additional comments (2)
src/Appwrite/Platform/Tasks/Screenshot.php (2)
210-212: LGTM: Variable override logic is correct.The override logic properly checks for CLI-provided variables and applies them after placeholder replacement, giving correct precedence (CLI variables > template defaults). Using
\array_key_exists()is appropriate for distinguishing between missing keys and falsy values.
251-252: No issues found. The deployment API parameters are correctly implemented.The change from
versiontoreferenceand addition oftype: tagcorrectly align with the Appwrite deployment API contract. The API endpoint explicitly allowstagas a valid type value alongsidebranchandcommit. Thereferenceparameter accepts commit hashes, branch names, or release tags as documented in the deployment endpoint specification.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
src/Appwrite/Platform/Tasks/Screenshot.php (2)
14-15: Validate_APP_DOMAINbefore constructing{apiEndpoint}placeholderThe
{apiEndpoint}placeholder is expanded using:$value = \str_replace('{apiEndpoint}', 'http://' . System::getEnv('_APP_DOMAIN', '') . '/v1', $value);If
_APP_DOMAINis unset or empty, this yieldshttp:///v1, which will break templates relying onapiEndpointand produce hard-to-debug failures. Adding an explicit validation here would make misconfiguration obvious, e.g.:+ $appDomain = System::getEnv('_APP_DOMAIN', ''); + if ($appDomain === '') { + throw new \Exception('_APP_DOMAIN environment variable is not set; required for {apiEndpoint} replacement in screenshot task.'); + } + - $value = \str_replace('{apiEndpoint}', 'http://' . System::getEnv('_APP_DOMAIN', '') . '/v1', $value); + $value = \str_replace('{apiEndpoint}', 'http://' . $appDomain . '/v1', $value);Based on learnings,
_APP_DOMAINis expected to always be set, so this should only trip in misconfigured environments.Also applies to: 213-215
186-205: Avoid creating API keys with all available scopesThe screenshot flow currently creates a project API key with every defined scope:
'_scopes' => \array_keys(Config::getParam('scopes', []))This violates least-privilege and risks exposing an overpowered key via site env vars (build logs, runtime introspection, etc.). Prefer a minimal, template-specific scope set, e.g.:
- Allow templates to declare required scopes (e.g.
$template['apiScopes']) and intersect them with the global list.- Fall back to a conservative default set if none are declared.
Example:
- $response = $client->call(..., [ - 'name' => 'Screenshot API key', - 'scopes' => \array_keys(Config::getParam('scopes', [])) - ]); + $allScopes = \array_keys(Config::getParam('scopes', [])); + $templateScopes = $template['apiScopes'] ?? []; + $scopes = empty($templateScopes) + ? ['databases.read', 'documents.read'] // or another minimal safe set + : \array_values(\array_intersect($templateScopes, $allScopes)); + + if (empty($scopes)) { + throw new \Exception('No valid scopes configured for Screenshot API key.'); + } + + $response = $client->call(..., [ + 'name' => 'Screenshot API key', + 'scopes' => $scopes, + ]);The rest of the key handling and injection into
$variables['APPWRITE_API_KEY']looks good.
🧹 Nitpick comments (2)
src/Appwrite/Platform/Tasks/Screenshot.php (2)
5-7: CLI--variablesusage and parsing look correct; consider minor clarity tweaksThe example
--variablesusage, new CLI param, and parsing logic together correctly support optional JSON env vars and fix the prior empty-string decode issue. You might still want to:
- Rename the
$variablesparameter to e.g.$variablesJsonand introduce a separate$variablesarray to avoid type confusion (parameter is declaredstringbut later holds an array).- Drop the now-redundant
if ($variables === null)check, sinceempty()short-circuits the empty-string case and non-empty invalid JSON already fails the\is_array()check.These are just cleanup/clarity improvements; behavior is fine as-is.
Also applies to: 29-30, 33-45
210-221: Variable interpolation/overrides work; be aware of placeholder andempty()semanticsThe interpolation and override flow is generally sound, but there are a couple of behavioral nuances to be aware of:
CLI overrides skip placeholder replacement: You first expand
{projectName},{projectId}, and{apiEndpoint}in the template default, then override with$variables[$name]when present. Any placeholders inside a CLI-provided value will remain literal. If you want CLI-provided values to also support placeholders, you’d need to either:
- Override first, then apply
str_replace, or- Re-run the replacements after the override.
empty($value)treats some valid strings as missing: Values like'0'will be considered empty and either skipped or trigger the “Missing required variable” exception. If you need to support such values, consider a stricter check such as$value === ''instead ofempty($value).Neither is necessarily wrong, but clarifying the intended behavior now will avoid surprises for template authors.
Also applies to: 223-223
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/Appwrite/Platform/Tasks/Screenshot.php(6 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-08T01:20:14.364Z
Learnt from: stnguyen90
Repo: appwrite/appwrite PR: 10119
File: app/controllers/api/account.php:1226-1232
Timestamp: 2025-07-08T01:20:14.364Z
Learning: In Appwrite, `_APP_DOMAIN` is a required environment variable that must always be set for the system to function properly.
Applied to files:
src/Appwrite/Platform/Tasks/Screenshot.php
🧬 Code graph analysis (1)
src/Appwrite/Platform/Tasks/Screenshot.php (1)
tests/e2e/Client.php (1)
Client(8-342)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
- GitHub Check: E2E Service Test (Realtime)
- GitHub Check: E2E Service Test (Users)
- GitHub Check: E2E Service Test (GraphQL)
- GitHub Check: E2E Service Test (Projects)
- GitHub Check: E2E Service Test (Avatars)
- GitHub Check: E2E Service Test (Locale)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E Service Test (Databases/TablesDB)
- GitHub Check: E2E Service Test (Databases/Legacy)
- GitHub Check: E2E Service Test (Health)
- GitHub Check: E2E Service Test (FunctionsSchedule)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (Site Screenshots)
- GitHub Check: Unit Test
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: E2E General Test
- GitHub Check: scan
🔇 Additional comments (2)
src/Appwrite/Platform/Tasks/Screenshot.php (2)
258-260: Deployment payload change (reference+type) aligns with template deploymentsSwitching the deployment payload from
versionto:'reference' => $template['providerVersion'], 'type' => 'tag',matches the deployment API’s expectation (reference + type) and should address the earlier “Param "type" is not optional.” 400 when creating template deployments. Please re-run the screenshot command for the new templates to confirm the deployment now succeeds end-to-end.
5-7: Usage doc for--variablesis clearThe added comment showing an example
--variablesJSON payload makes the CLI usage self-explanatory and matches the parsing logic below. No changes needed.


What does this PR do?
Add formspree and react-admin templates to sites
Test Plan
(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Screenshots may also be helpful.)
Related PRs and Issues
Checklist