From 790bd33aac1f6459d6f4fdb858cbf46b07ec0240 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Thu, 16 Feb 2023 10:15:47 +0100 Subject: [PATCH] Updates docs --- web/docs/language/features.md | 103 +++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 27 deletions(-) diff --git a/web/docs/language/features.md b/web/docs/language/features.md index 15f1b348c7..276c62e942 100644 --- a/web/docs/language/features.md +++ b/web/docs/language/features.md @@ -485,7 +485,7 @@ In other words, the hook returns a function whose API matches the original Actio The `useAction` hook accepts two arguments: - `actionFn` (required) - The Wasp Action (i.e., the client-side query function generated by Wasp based on a query declaration) you wish to enhance. -- `actionOptions` (optional) - An object configuring the extra features you want to add to the given Action. While this argument is technically optional, there is no point in using the `useAction` hook without providing it (it would be the same as using the Action directly). The Action options object supports the following fields: +- `actionOptions` (optional) - An object configuring the extra features you want to add to the given Action. While this argument is technically optional, there is no point in using the `useAction` hook without providing it (it would be the same as using the Action directly). The Action options object supports the following fields: - `optimisticUpdates` (optional) - An array of objects where each object defines an [optimistic update](https://stackoverflow.com/a/33009713) to perform on the query cache. To define an optimistic update, you must specify the following properties: - `getQuerySpecifier` (required) - A function returning the query specifier (i.e., a value used to address the query you want to update). A query specifier is an array specifying the query function and arguments. For example, to optimistically update the query used with `useQuery(fetchFilteredTasks, {isDone: true }]`, your `getQuerySpecifier` function would have to return the array `[fetchFilteredTasks, { isDone: true}]`. Wasp will forward the argument you pass into the decorated Action to this function (i.e., you can use the properties of the added/change item to address the query). - `updateQuery` (required) - The function used to perform the optimistic update. It should return the desired state of the cache. Wasp will call it with the following arguments: @@ -494,7 +494,7 @@ The `useAction` hook accepts two arguments: **NOTE:** The `updateQuery` function must be a pure function. It must return the desired cache value identified by the `getQuerySpecifier` function and _must not_ perform any side effects. Also, make sure you only update the query caches affected by your action causing the optimistic update (Wasp cannot yet verify this). Finally, your implementation of the `updateQuery` function should work correctly regardless of the state of `oldData` (e.g., don't rely on array positioning). If you need to do something else during your optimistic update, you can directly use _react-query_'s lower-level API (read more about it [here](#advanced-usage)). -Here's an example showing how to configure the Action from the previous example to perform an optimistic update: +Here's an example showing how to configure the Action from the previous example to perform an optimistic update: ```jsx {3,9,10,11,12,13,14,15,16,27} title=src/client/pages/Task.js import React from 'react' import { useQuery } from '@wasp/queries' @@ -532,7 +532,7 @@ const TaskPage = ({ id }) => { ) } -export default TaskPage +export default TaskPage ``` #### Advanced usage The `useAction` hook currently only supports specifying optimistic updates. You can expect more features in future versions of Wasp. @@ -590,8 +590,8 @@ If you have server tasks that you do not want to handle as part of the normal re * persist between server restarts * can be retried if they fail * can be delayed until the future - * can have a recurring schedule! - + * can have a recurring schedule! + Some examples where you may want to use a `job` on the server include sending an email, making an HTTP request to some external API, or doing some nightly calculations. ### Job Executors @@ -606,7 +606,7 @@ Currently, Wasp supports only one type of job executor, which is `PgBoss`, but i We have selected [pg-boss](https://github.com/timgit/pg-boss/) as our first job executor to handle the low-volume, basic job queue workloads many web applications have. By using PostgreSQL (and [SKIP LOCKED](https://www.2ndquadrant.com/en/blog/what-is-select-skip-locked-for-in-postgresql-9-5/)) as its storage and synchronization mechanism, it allows us to provide many job queue pros without any additional infrastructure or complex management. -:::info +:::info Keep in mind that pg-boss jobs run alongside your other server-side code, so they are not appropriate for CPU-heavy workloads. Additionally, some care is required if you modify scheduled jobs. Please see pg-boss details below for more information.
@@ -654,9 +654,9 @@ console.log(await submittedJob.pgBoss.details()) await mySpecialJob.delay(10).submit({ job: "args" }) ``` -And that is it! Your job will be executed by the job executor (pg-boss, in this case) as if you called `foo({ job: "args" })`. +And that is it! Your job will be executed by the job executor (pg-boss, in this case) as if you called `foo({ job: "args" })`. -Note that in our example, `foo` takes an argument, but this does not always have to be the case. It all depends on how you've implemented your worker function. +Note that in our example, `foo` takes an argument, but this does not always have to be the case. It all depends on how you've implemented your worker function. ### Recurring jobs @@ -715,7 +715,7 @@ job mySpecialJob { // Can reference context.entities.Task, for example. } ``` - + - ##### `executorOptions: dict` (optional) Executor-specific default options to use when submitting jobs. These are passed directly through and you should consult the documentation for the job executor. These can be overridden during invocation with `submit()` or in a `schedule`. @@ -723,15 +723,15 @@ job mySpecialJob { See the docs for [pg-boss](https://github.com/timgit/pg-boss/blob/8.0.0/docs/readme.md#sendname-data-options). #### `schedule: dict` (optional) - + - ##### `cron: string` (required) A 5-placeholder format cron expression string. See rationale for minute-level precision [here](https://github.com/timgit/pg-boss/blob/8.0.0/docs/readme.md#scheduling). - + _If you need help building cron expressions, Check out_ [Crontab guru](https://crontab.guru/#0_*_*_*_*). - + - ##### `args: JSON` (optional) The arguments to pass to the `perform.fn` function when invoked. - + - ##### `executorOptions: dict` (optional) Executor-specific options to use when submitting jobs. These are passed directly through and you should consult the documentation for the job executor. The `perform.executorOptions` are the default options, and `schedule.executorOptions` can override/extend those. @@ -814,7 +814,7 @@ In the future, we will add support for picking any version you like, but we have Wasp provides authentication and authorization support out-of-the-box. Enabling it for your app is optional and can be done by configuring the `auth` field of the `app` declaration: -```c +```c app MyApp { title: "My app", //... @@ -855,7 +855,7 @@ Check out this [section of our Todo app tutorial](/docs/tutorials/todo-app/06-au Path where a successfully authenticated user will be sent upon successful login/signup. Default value is "/". -:::note +:::note Automatic redirect on successful login only works when using the Wasp provided [`Signup` and `Login` forms](#high-level-api) ::: @@ -864,7 +864,7 @@ Automatic redirect on successful login only works when using the Wasp provided [ `usernameAndPassword` authentication method makes it possible to signup/login into the app by using a username and password. This method requires that `userEntity` specified in `auth` contains `username: string` and `password: string` fields: -```c +```c app MyApp { title: "My app", //... @@ -916,10 +916,10 @@ export const signUp = async (args, context) => { // ... const newUser = context.entities.User.create({ - data: { - username: args.username, + data: { + username: args.username, password: args.password // password hashed automatically by Wasp! 🐝 - } + } }) // Your custom code after sign-up. @@ -937,8 +937,8 @@ You don't need to worry about hashing the password yourself! Even when you are u To disable/enable default validations, or add your own, you can modify your custom signUp function like so: ```js const newUser = context.entities.User.create({ - data: { - username: args.username, + data: { + username: args.username, password: args.password // password hashed automatically by Wasp! 🐝 }, _waspSkipDefaultValidations: false, // can be omitted if false (default), or explicitly set to true @@ -1133,7 +1133,7 @@ import AuthError from '@wasp/core/AuthError.js' ``` ## Social Login Providers (OAuth 2.0) -Wasp allows you to easily add social login providers to your app. +Wasp allows you to easily add social login providers to your app. The following is a list of links to guides that will help you get started with the currently supported providers: - [GitHub](/docs/integrations/github) @@ -1150,7 +1150,7 @@ When using Social Login Providers, Wasp gives you the following options: -```c +```c auth: { userEntity: User, externalAuthEntity: SocialLogin, @@ -1159,7 +1159,7 @@ When using Social Login Providers, Wasp gives you the following options: }, } ``` - +

Add google: {} to your auth.methods dictionary to use it with default settings

By default, Wasp expects you to set two environment variables in order to use Google authentication:

    @@ -1266,7 +1266,7 @@ If you would like to allow the user to select their own username, or some other Alternatively, you could add a `displayName` property to your User entity and assign it using the details of their provider account. Below is an example of how to do this by using: - the `getUserFieldsFn` function to configure the user's `username` or `displayName` from their provider account -We also show you how to customize the configuration of the Provider's settings using: +We also show you how to customize the configuration of the Provider's settings using: - the `configFn` function ```c title=main.wasp {9,10,13,14,26} @@ -1304,7 +1304,7 @@ psl=} ``` -#### `configFn` +#### `configFn` This function should return an object with the following shape: @@ -1377,13 +1377,14 @@ This function should return the user fields to use when creating a new user upon ## Client configuration You can configure the client using the `client` field inside the `app` -declaration, +declaration, ```c app MyApp { title: "My app", // ... client: { + rootComponent: import Root from "@client/Root.jsx", setupFn: import mySetupFunction from "@client/myClientSetupCode.js" } } @@ -1391,6 +1392,54 @@ app MyApp { `app.client` is a dictionary with the following fields: +#### `rootComponent: ClientImport` (optional) + +`rootComponent` defines the root component of your client application. It is +expected to be a React component, and Wasp will use it to wrap your entire app. +It must render its children, which are the actual pages of your application. + +You can use it to define a common layout for your application: + +```jsx title="src/client/Root.jsx" +export default async function Root({ children }) { + return ( +
    +
    +

    My App

    +
    + {children} +
    +

    My App footer

    +
    +
    + ) +} +``` + +You can use it to setup various providers that your application needs: + +```jsx title="src/client/Root.jsx" +import store from './store' +import { Provider } from 'react-redux' + +export default async function Root({ children }) { + return ( + + {children} + + ) +} + +function App({ children }) { + return ( +
    +

    My App

    + {children} +
    + ) +} +``` + #### `setupFn: ClientImport` (optional) `setupFn` declares a JavaScript function that Wasp executes on the client