diff --git a/content/1.getting-started/1.create-a-project.md b/content/1.getting-started/1.create-a-project.md index 2af1b592..5a77420b 100644 --- a/content/1.getting-started/1.create-a-project.md +++ b/content/1.getting-started/1.create-a-project.md @@ -55,7 +55,6 @@ Create a `docker-compose.yml` file in the `directus` directory: ```yaml [docker-compose.yml] -version: "3" services: directus: image: directus/directus:10.10.1 @@ -66,7 +65,6 @@ services: - ./uploads:/directus/uploads - ./extensions:/directus/extensions environment: - KEY: "replace-with-random-value" SECRET: "replace-with-random-value" ADMIN_EMAIL: "admin@example.com" ADMIN_PASSWORD: "d1r3ctu5" @@ -82,7 +80,7 @@ services: - The `volumes` section maps internal `directus/database` and `directus/uploads` to our local file system alongside the `docker-compose.yml` - meaning data is backed up outside of Docker containers. - The `environment` section contains any [configuration environment variables](/configuration/overview) we wish to set. - - `KEY` and `SECRET` are required and should be long random values. `KEY` is used for telemetry and health tracking, and `SECRET` is used to sign access tokens. + - `SECRET` is required and should be a long random value. `SECRET` is used to sign access tokens. - `ADMIN_EMAIL` and `ADMIN_PASSWORD` is the initial admin user credentials on first launch. - `DB_CLIENT` and `DB_FILENAME` are defining the connection to your database. - `WEBSOCKETS_ENABLED` is not required, but enables [Directus Realtime](/realtime/quickstart). diff --git a/content/10.extensions/3.app-extensions/1.interfaces.md b/content/10.extensions/3.app-extensions/1.interfaces.md index d13ff3ab..ac8c84f9 100644 --- a/content/10.extensions/3.app-extensions/1.interfaces.md +++ b/content/10.extensions/3.app-extensions/1.interfaces.md @@ -18,10 +18,11 @@ The `index.js` or `index.ts` file exports an object that is read by Directus. It ### Entrypoint Example -```vue +```js +import { defineInterface } from '@directus/extensions-sdk' import InterfaceComponent from './interface.vue'; -export default { +export default defineInterface({ id: 'custom', name: 'Custom', icon: 'box', @@ -39,7 +40,7 @@ export default { } }, ], -}; +}); ``` ### Properties @@ -111,4 +112,4 @@ The interface component can emit the following events that will be recognized by | `input` | Update the value of the field. | | `setFieldValue` | Used to set the value of other fields. | -:partial{content="extensions-app-internals"} \ No newline at end of file +:partial{content="extensions-app-internals"} diff --git a/content/10.extensions/3.app-extensions/2.displays.md b/content/10.extensions/3.app-extensions/2.displays.md index e6d65f28..6129320d 100644 --- a/content/10.extensions/3.app-extensions/2.displays.md +++ b/content/10.extensions/3.app-extensions/2.displays.md @@ -19,9 +19,10 @@ The `index.js` or `index.ts` file exports an object that is read by Directus. It ### Entrypoint Example ```js +import { defineInterface } from '@directus/extensions-sdk' import DisplayComponent from './display.vue'; -export default { +export default defineInterface({ id: 'custom', name: 'Custom', icon: 'box', @@ -29,7 +30,7 @@ export default { component: DisplayComponent, options: null, types: ['string'], -}; +}); ``` ### Properties @@ -91,7 +92,9 @@ The current value of the field is provided to the component via the `value` prop Instead of defining the component inside a separate Vue file, you can use a functional component. This allows you to make small displays that don't need a full component. ```js -export default { +import { defineInterface } from '@directus/extensions-sdk' + +export default defineInterface({ id: 'custom', name: 'Custom', icon: 'box', @@ -101,7 +104,7 @@ export default { }, options: null, types: ['string'], -}; +}); ``` -:partial{content="extensions-app-internals"} \ No newline at end of file +:partial{content="extensions-app-internals"} diff --git a/content/10.extensions/3.app-extensions/3.layouts.md b/content/10.extensions/3.app-extensions/3.layouts.md index 3eada19d..73ee68c5 100644 --- a/content/10.extensions/3.app-extensions/3.layouts.md +++ b/content/10.extensions/3.app-extensions/3.layouts.md @@ -20,9 +20,10 @@ The `index.js` or `index.ts` file exports an object that is read by Directus. It ```js import { ref } from 'vue'; +import { defineInterface } from '@directus/extensions-sdk' import LayoutComponent from './layout.vue'; -export default { +export default defineInterface({ id: 'custom', name: 'Custom', icon: 'box', @@ -36,7 +37,7 @@ export default { const name = ref('Custom Layout'); return { name }; }, -}; +}); ``` ### Properties @@ -116,4 +117,4 @@ The layout component can emit the following events that will be recognized by Di | `update:layoutOptions` | Update the user's currently saved layout options. | | `update:layoutQuery` | Update the user's layout query parameters. | -:partial{content="extensions-app-internals"} \ No newline at end of file +:partial{content="extensions-app-internals"} diff --git a/content/10.extensions/3.app-extensions/4.panels.md b/content/10.extensions/3.app-extensions/4.panels.md index 13171835..3e2938d4 100644 --- a/content/10.extensions/3.app-extensions/4.panels.md +++ b/content/10.extensions/3.app-extensions/4.panels.md @@ -19,9 +19,10 @@ The `index.js` or `index.ts` file exports an object that is read by Directus. It ### Entrypoint Example ```js +import { defineInterface } from '@directus/extensions-sdk' import PanelComponent from './panel.vue'; -export default { +export default defineInterface({ id: 'custom', name: 'Custom', icon: 'box', @@ -40,7 +41,7 @@ export default { }, }, ], -}; +}); ``` ### Properties diff --git a/content/10.extensions/3.app-extensions/5.modules.md b/content/10.extensions/3.app-extensions/5.modules.md index 372e7fd6..34ce2e4e 100644 --- a/content/10.extensions/3.app-extensions/5.modules.md +++ b/content/10.extensions/3.app-extensions/5.modules.md @@ -25,9 +25,10 @@ The `index.js` or `index.ts` file exports an object that is read by Directus. It ## Entrypoint Example ```js +import { defineInterface } from '@directus/extensions-sdk' import ModuleComponent from './module.vue'; -export default { +export default defineInterface({ id: 'custom', name: 'Custom', icon: 'box', @@ -37,7 +38,7 @@ export default { component: ModuleComponent, }, ], -}; +}); ``` ### Properties @@ -96,4 +97,4 @@ sidebar, header, and the main content area. Named slots can be used to add addit | `splitView` | Renders content in the split view area (only if the private layout has the split-view prop set to true). | | `sidebar` | Populates the sidebar area in the Directus interface. | -:partial{content="extensions-app-internals"} \ No newline at end of file +:partial{content="extensions-app-internals"} diff --git a/content/10.extensions/3.app-extensions/6.themes.md b/content/10.extensions/3.app-extensions/6.themes.md index dda2d390..25ee7d00 100644 --- a/content/10.extensions/3.app-extensions/6.themes.md +++ b/content/10.extensions/3.app-extensions/6.themes.md @@ -90,4 +90,4 @@ fontFamily: 'Comic Sans MS, sans-serif' fontFamily: '"Yesteryear", sans-serif' ``` -When using a Google Font, ensure the configured weight is available for the selected font. \ No newline at end of file +When using a Google Font, ensure the configured weight is available for the selected font. diff --git a/content/10.extensions/3.app-extensions/7.ui-library.md b/content/10.extensions/3.app-extensions/7.ui-library.md index de74d19e..48b2e2bd 100644 --- a/content/10.extensions/3.app-extensions/7.ui-library.md +++ b/content/10.extensions/3.app-extensions/7.ui-library.md @@ -51,12 +51,12 @@ Refer to the full list of component based CSS variables [in our source code](htt The Directus UI components are designed with flexibility and customization in mind. However, you may need to create your own components using shared styling. Directus exposes several CSS variables for both light and dark themes. -Examples of CSS variables include `--border-normal`, `--foreground-normal` `-purple`, `--module-background`, and -`--overlay-color`. +Examples of CSS variables include `--theme--border-normal`, `--theme--foreground-normal` `--theme--purple`, `--theme--module-background`, and +`--theme--overlay-color`. ::callout{type="info" title="Explore Light and Dark Theme CSS Variables"} Refer to our [source code](https://github.com/directus/directus/tree/main/app/src/styles/themes) for a full list of CSS variables. -:: \ No newline at end of file +:: diff --git a/content/4.auth/1.quickstart.md b/content/4.auth/1.quickstart.md index be91cf65..fc2f745f 100644 --- a/content/4.auth/1.quickstart.md +++ b/content/4.auth/1.quickstart.md @@ -35,6 +35,8 @@ Log out of the Data Studio. From the Sign In screen, you will see a new option t Open your terminal and run the following command to register a new user. +::snippets +#rest ```bash [Terminal] curl \ --request POST \ @@ -43,12 +45,29 @@ curl \ --url 'https://directus.example.com/register' ``` +#graphql +```graphql +mutation { + users_register(email: "hello@example.com", password: "d1r3ctu5") +} +``` + +#sdk +```js +import { createDirectus, rest, registerUser } from '@directus/sdk'; + +const client = createDirectus('https://directus.example.com').with(rest()); + +const result = await client.request(registerUser('hello@example.com', 'd1r3ctu5')); +``` +:: + Go to the user directory by clicking :icon{name="user-directory"} in the module bar and you should see a new user has been created. ## Logging In -To log in and get an access token, run the following command. - +::snippets +#rest ```bash [Terminal] curl \ --request POST \ @@ -57,6 +76,29 @@ curl \ --url 'https://directus.example.com/auth/login' ``` +#graphql +```graphql +mutation { + auth_login(email: "hello@example.com", password: "d1r3ctu5") { + access_token + refresh_token + } +} +``` + +#sdk +```js +import { createDirectus, authentication } from '@directus/sdk'; + +const email = "hello@example.com"; +const password = "d1r3ctu5"; + +const client = createDirectus('http://directus.example.com').with(authentication()); + +const token = await client.login(email, password); +``` +:: + ## Authenticating Requests You can use the access token while making requests. If your token has expired, you must refresh it. diff --git a/content/4.auth/5.email-login.md b/content/4.auth/5.email-login.md index b6ba4088..4a4293a8 100644 --- a/content/4.auth/5.email-login.md +++ b/content/4.auth/5.email-login.md @@ -22,13 +22,41 @@ Read more about creating users. You can authenticate as a user to receive a standard token. -```json [POST /auth/login] -{ - "email": "hello@example.com", - "password": "d1r3ctu5" +## Logging In + +::snippets +#rest +```bash [Terminal] +curl \ +--request POST \ +--header 'Content-Type: application/json' \ +--data '{ "email": "hello@example.com", "password": "d1r3ctu5" }' \ +--url 'https://directus.example.com/auth/login' +``` + +#graphql +```graphql +mutation { + auth_login(email: "hello@example.com", password: "d1r3ctu5") { + access_token + refresh_token + } } ``` +#sdk +```js +import { createDirectus, authentication } from '@directus/sdk'; + +const email = "hello@example.com"; +const password = "d1r3ctu5"; + +const client = createDirectus('http://directus.example.com').with(authentication()); + +const token = await client.login(email, password); +``` +:: + If the user has [two-factor authentication](/auth/2fa) enabled, an `otp` (one-time password) can be passed as an additional property. The response will contain a standard token. :partial{content="snippet-auth-token"} @@ -37,56 +65,176 @@ If the user has [two-factor authentication](/auth/2fa) enabled, an `otp` (one-ti -If you wish to receive and store a session cookie, add a `mode` property when logging in. The token won't be returned in JSON response. +If you wish to receive and store a session cookie, add a `mode` property when logging in. +::snippets +#rest ```json [POST /auth/login] { "email": "hello@example.com", - "password": "d1r3ctu5", - "mode": "session" + "password": "d1r3ctu5" } ``` +The token won't be returned in JSON response. + +#graphql +```graphql +mutation { + auth_login(email: "hello@example.com", password: "d1r3ctu5", mode: "session") { + access_token + refresh_token + } +} +``` + +#sdk +```js +import { createDirectus, authentication } from '@directus/sdk'; + +const email = "hello@example.com"; +const password = "d1r3ctu5"; + +const client = createDirectus('http://directus.example.com').with(authentication()); + +const token = await client.login(email, password, {mode: "session"}); +``` +:: ## Refresh Retrieve a new access token by refreshing it. +::snippets +#rest ```json [POST /auth/refresh] { "refresh_token": "Xp2tTNAdLYfnaAOOjt3oetyCWtobKKUIeEXj..." } ``` +#graphql + +```graphql +mutation { + auth_refresh(refresh_token: "refresh_token") { + access_token + refresh_token + } +} +``` + +# sdk + +```js +import { createDirectus, authentication, rest, refresh } from '@directus/sdk'; + +const client = createDirectus('directus_project_url').with(authentication()).with(rest()); + +// refresh http request using json +const result = await client.request(refresh('json', refresh_token)); +``` + ### Refreshing a Cookie You do not need to provide the `refresh_token`, but you must specify the `mode`. +::snippets +#rest ```json [POST /auth/refresh] { "mode": "session" } ``` +#graphql +```graphql +mutation { + auth_refresh(refresh_token: "refresh_token") { + access_token + refresh_token + } +} +``` + +#sdk +```js +import { createDirectus, authentication, rest, refresh } from '@directus/sdk'; + +const client = createDirectus('directus_project_url').with(authentication()).with(rest()); + +// refresh http request using a cookie +const result = await client.request(refresh('cookie')); +``` +:: + ## Logout Invalidate the refresh token and destroy the user's session. +::snippets +#rest ```json [POST /auth/logout] { "refresh_token": "Xp2tTNAdLYfnaAOOjt3oetyCWtobKKUIeEXj..." } ``` +#graphql +```graphql +mutation { + auth_logout(refresh_token: "Xp2tTNAdLYfnaAOOjt3oetyCWtobKKUIeEXj...") +} +``` + +#sdk +```js +import { createDirectus, authentication, rest, logout } from '@directus/sdk'; + +const client = createDirectus('directus_project_url').with(authentication()).with(rest()); + +const result = await client.logout(); +``` + +You can also log out using the http request mechanism: + +```js +import { createDirectus, authentication, rest, logout } from '@directus/sdk'; + +const client = createDirectus('directus_project_url').with(authentication()).with(rest()); + +const result = await client.request(logout(refresh_token)); +``` +:: + ### Invalidating a Cookie You do not need to provide the `refresh_token`, but you must specify the `mode`. This will immediately invalidate and delete the cookie. +::snippets +#rest ```json [POST /auth/logout] { "mode": "session" } ``` +#graphql +```graphql +mutation { + auth_logout(mode: "session") +} +``` + +#sdk +```js +import { createDirectus, authentication, rest, logout } from '@directus/sdk'; + +const client = createDirectus('directus_project_url').with(authentication()).with(rest()); + +const result = await client.logout({mode: "session"}); +``` +:: + ## Password Reset Requesting a password reset will send an email to the user with a URL to the Data Studio to reset their password. @@ -111,6 +259,8 @@ When using the request reset password endpoint, add a `reset_url` property. The Your application must extract this value, collect the new user's password, and send both to the reset password endpoint. +::snippets +#rest ```json [POST /auth/password/reset] { "token": "Xp2tTNAdLYfnaAOOjt3oetyCWtobKKUIeEXj", @@ -118,6 +268,27 @@ Your application must extract this value, collect the new user's password, and s } ``` +#graphql + +```graphql +mutation { + auth_password_reset(token: "Xp2tTNAdLYfnaAOOjt3oetyCWtobKKUIeEXj", password: "d1r3ctu5!") +} +``` + +#sdk + +```js +import { createDirectus, rest, passwordReset } from '@directus/sdk'; + +const client = createDirectus('directus_project_url').with(rest()); + +const reset_token = "Xp2tTNAdLYfnaAOOjt3oetyCWtobKKUIeEXj"; +const new_password = "d1r3ctu5!"; + +const result = await client.request(passwordReset(reset_token, new_password)); +``` + ::callout{type="dev-docs" url="/configuration/security-limits"} The `PASSWORD_RESET_URL_ALLOW_LIST` environment variable must be configured. :: diff --git a/content/6.files/1.quickstart.md b/content/6.files/1.quickstart.md index 2c05c7eb..b1d65be8 100644 --- a/content/6.files/1.quickstart.md +++ b/content/6.files/1.quickstart.md @@ -24,7 +24,7 @@ The uploaded file is immediately available via the Data Studio for users with th You can access files via URL in your applications by using the following URL pattern: ``` -https://example.directus.app/assets/file-id?access_token=token +https://example.directus.app/assets/?access_token=token ``` The token must belong to a user who has access to read files in the `directus_files` collection. If the public role has read access, you can omit the `access_token` parameter. @@ -46,7 +46,7 @@ width=200 Your new URL should look like this: ``` -https://example.directus.app/assets/file-id?access_token=token&width=200 +https://example.directus.app/assets/?access_token=token&width=200 ``` The asset will be transformed, saved to your asset storage, and returned to the user. On subsequent requests, the already transformed asset will be returned.