Docs modifications (#5804)
- Fixes #5504 - Fixes #5503 - Return 404 when the page does not exist - Modified the footer in order to align it properly - Removed "noticed something to change" in each table of content - Fixed the URLs of the edit module - Added the edit module to Developers - Fixed header style on the REST API page. - Edited the README to point to Developers - Fixed selected state when clicking on sidebar elements --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
@ -21,4 +21,6 @@ You should also expose services that you want to use in other modules. Exposing
|
||||
|
||||
When you declare a variable as `any`, TypeScript's type checker doesn't perform any type checking, making it possible to assign any type of values to the variable. TypeScript uses type inference to determine the type of variable based on the value. By declaring it as `any`, TypeScript can no longer infer the type. This makes it hard to catch type-related errors during development, leading to runtime errors and makes the code less maintainable, less reliable, and harder to understand for others.
|
||||
|
||||
This is why everything should have a type. So if you create a new object with a first name and last name, you should create an interface or type that contains a first name and last name that defines the shape of the object you are manipulating.
|
||||
This is why everything should have a type. So if you create a new object with a first name and last name, you should create an interface or type that contains a first name and last name that defines the shape of the object you are manipulating.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -38,3 +38,5 @@ To fetch data, the process involves making queries through the /graphql endpoint
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/images/docs/server/custom-object-schema.png" alt="Query the /graphql endpoint to fetch data" />
|
||||
</div>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
|
||||
@ -49,3 +49,5 @@ Change the corresponding record in the Table `core.featureFlag`:
|
||||
| id | key | workspaceId | value |
|
||||
|----------|--------------------------|---------------|--------|
|
||||
| Random | `IS_FEATURENAME_ENABLED` | WorkspaceID | `true` |
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -129,4 +129,6 @@ Includes factories that generate `pg_graphql` queries.
|
||||
|
||||
### Workspace Query Runner
|
||||
|
||||
Runs the generated queries on the database and parses the result.
|
||||
Runs the generated queries on the database and parses the result.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -43,3 +43,4 @@ class CustomWorker {
|
||||
}
|
||||
```
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -77,4 +77,6 @@ Here's what the tech stack now looks like.
|
||||
- [ESLint](https://eslint.org/)
|
||||
|
||||
**Development**
|
||||
- [AWS EKS](https://aws.amazon.com/eks/)
|
||||
- [AWS EKS](https://aws.amazon.com/eks/)
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -73,3 +73,5 @@ yarn deploy
|
||||
```bash
|
||||
zapier
|
||||
```
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
|
||||
@ -13,3 +13,5 @@ You can also ask for help on [Discord](https://discord.gg/cx5n4Jzs57).
|
||||
## Feature Requests
|
||||
|
||||
If you're not sure it's a bug and you feel it's closer to a feature request, then you should probably [open a discussion instead](https://github.com/twentyhq/twenty/discussions/new).
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -327,3 +327,4 @@ type Form = z.infer<typeof validationSchema>;
|
||||
|
||||
Always perform thorough manual testing before proceeding to guarantee that modifications haven’t caused disruptions elsewhere, given that tests have not yet been extensively integrated.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -110,3 +110,5 @@ You can import other module code from any module except for the `ui` folder. Thi
|
||||
### Internal
|
||||
|
||||
Each part (hooks, states, ...) of a module can have an `internal` folder, which contains parts that are just used within the module.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -77,3 +77,5 @@ See [best practices](/contributor/frontend/best-practices#state-management) for
|
||||
Jest is mainly for testing utility functions, and not components themselves.
|
||||
|
||||
Storybook is for testing the behavior of isolated components, as well as displaying the design system.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -4,19 +4,175 @@ icon: TbKeyboard
|
||||
image: /images/user-guide/table-views/table.png
|
||||
---
|
||||
|
||||
You can intercept any hotkey combination and execute a custom action.
|
||||
## Introduction
|
||||
|
||||
There's a thin wrapper on top of [react-hotkeys-hook](https://react-hotkeys-hook.vercel.app/docs/intro) that makes it more performant and avoids unnecessary re-renders.
|
||||
When you need to listen to a hotkey, you would normally use the `onKeyDown` event listener.
|
||||
|
||||
There's also a wrapper hook `useScopedHotkeys` that makes it easy to manage scopes.
|
||||
In `twenty-front` however, you might have conflicts between same hotkeys that are used in different components, mounted at the same time.
|
||||
|
||||
```ts
|
||||
useScopedHotkeys(
|
||||
'ctrl+k,meta+k',
|
||||
() => {
|
||||
openCommandMenu();
|
||||
},
|
||||
AppHotkeyScope.CommandMenu,
|
||||
[openCommandMenu],
|
||||
);
|
||||
For example, if you have a page that listens for the Enter key, and a modal that listens for the Enter key, with a Select component inside that modal that listens for the Enter key, you might have a conflict when all are mounted at the same time.
|
||||
|
||||
## The `useScopedHotkeys` hook
|
||||
|
||||
To handle this problem, we have a custom hook that makes it possible to listen to hotkeys without any conflict.
|
||||
|
||||
You place it in a component and it will listen to the hotkeys only when the component is mounted AND when the specified **hotkey scope** is active.
|
||||
|
||||
## How to listen for hotkeys in practice ?
|
||||
|
||||
There are two steps involved in setting up hotkey listening :
|
||||
1. Set the [hotkey scope](#what-is-a-hotkey-scope-) that will listen to hotkeys
|
||||
2. Use the `useScopedHotkeys` hook to listen to hotkeys
|
||||
|
||||
Setting up hotkey scopes is required even in simple pages, because other UI elements like left menu or command menu might also listen to hotkeys.
|
||||
|
||||
## Use cases for hotkeys
|
||||
|
||||
In general, you'll have two use cases that require hotkeys :
|
||||
1. In a page or a component mounted in a page
|
||||
2. In a modal-type component that takes the focus due to a user action
|
||||
|
||||
The second use case can happen recursively : a dropdown in a modal for example.
|
||||
|
||||
### Listening to hotkeys in a page
|
||||
|
||||
Example :
|
||||
|
||||
```tsx
|
||||
const PageListeningEnter = () => {
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
// 1. Set the hotkey scope in a useEffect
|
||||
useEffect(() => {
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
ExampleHotkeyScopes.ExampleEnterPage,
|
||||
);
|
||||
|
||||
// Revert to the previous hotkey scope when the component is unmounted
|
||||
return () => {
|
||||
goBackToPreviousHotkeyScope();
|
||||
};
|
||||
}, [goBackToPreviousHotkeyScope, setHotkeyScopeAndMemorizePreviousScope]);
|
||||
|
||||
// 2. Use the useScopedHotkeys hook
|
||||
useScopedHotkeys(
|
||||
Key.Enter,
|
||||
() => {
|
||||
// Some logic executed on this page when the user presses Enter
|
||||
// ...
|
||||
},
|
||||
ExampleHotkeyScopes.ExampleEnterPage,
|
||||
);
|
||||
|
||||
return <div>My page that listens for Enter</div>;
|
||||
};
|
||||
```
|
||||
|
||||
### Listening to hotkeys in a modal-type component
|
||||
|
||||
For this example we'll use a modal component that listens for the Escape key to tell it's parent to close it.
|
||||
|
||||
Here the user interaction is changing the scope.
|
||||
|
||||
```tsx
|
||||
const ExamplePageWithModal = () => {
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
const handleOpenModalClick = () => {
|
||||
// 1. Set the hotkey scope when user opens the modal
|
||||
setShowModal(true);
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
ExampleHotkeyScopes.ExampleModal,
|
||||
);
|
||||
};
|
||||
|
||||
const handleModalClose = () => {
|
||||
// 1. Revert to the previous hotkey scope when the modal is closed
|
||||
setShowModal(false);
|
||||
goBackToPreviousHotkeyScope();
|
||||
};
|
||||
|
||||
return <div>
|
||||
<h1>My page with a modal</h1>
|
||||
<button onClick={handleOpenModalClick}>Open modal</button>
|
||||
{showModal && <MyModalComponent onClose={handleModalClose} />}
|
||||
</div>;
|
||||
};
|
||||
```
|
||||
|
||||
Then in the modal component :
|
||||
|
||||
```tsx
|
||||
const MyDropdownComponent = ({ onClose }: { onClose: () => void }) => {
|
||||
// 2. Use the useScopedHotkeys hook to listen for Escape.
|
||||
// Note that escape is a common hotkey that could be used by many other components
|
||||
// So it's important to use a hotkey scope to avoid conflicts
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
() => {
|
||||
onClose()
|
||||
},
|
||||
ExampleHotkeyScopes.ExampleModal,
|
||||
);
|
||||
|
||||
return <div>My modal component</div>;
|
||||
};
|
||||
```
|
||||
|
||||
It's important to use this pattern when you're not sure that just using a useEffect with mount/unmount will be enough to avoid conflicts.
|
||||
|
||||
Those conflicts can be hard to debug, and it might happen more often than not with useEffects.
|
||||
|
||||
## What is a hotkey scope ?
|
||||
|
||||
A hotkey scope is a string that represents a context in which the hotkeys are active. It is generally encoded as an enum.
|
||||
|
||||
When you change the hotkey scope, the hotkeys that are listening to this scope will be enabled and the hotkeys that are listening to other scopes will be disabled.
|
||||
|
||||
You can set only one scope at a time.
|
||||
|
||||
As an example, the hotkey scopes for each page are defined in the `PageHotkeyScope` enum:
|
||||
|
||||
```tsx
|
||||
export enum PageHotkeyScope {
|
||||
Settings = 'settings',
|
||||
CreateWokspace = 'create-workspace',
|
||||
SignInUp = 'sign-in-up',
|
||||
CreateProfile = 'create-profile',
|
||||
PlanRequired = 'plan-required',
|
||||
ShowPage = 'show-page',
|
||||
PersonShowPage = 'person-show-page',
|
||||
CompanyShowPage = 'company-show-page',
|
||||
CompaniesPage = 'companies-page',
|
||||
PeoplePage = 'people-page',
|
||||
OpportunitiesPage = 'opportunities-page',
|
||||
ProfilePage = 'profile-page',
|
||||
WorkspaceMemberPage = 'workspace-member-page',
|
||||
TaskPage = 'task-page',
|
||||
}
|
||||
```
|
||||
|
||||
Internally, the currently selected scope is stored in a Recoil state that is shared across the application :
|
||||
|
||||
```tsx
|
||||
export const currentHotkeyScopeState = createState<HotkeyScope>({
|
||||
key: 'currentHotkeyScopeState',
|
||||
defaultValue: INITIAL_HOTKEYS_SCOPE,
|
||||
});
|
||||
```
|
||||
|
||||
But this Recoil state should never be handled manually ! We'll see how to use it in the next section.
|
||||
|
||||
## How is it working internally ?
|
||||
|
||||
We made a thin wrapper on top of [react-hotkeys-hook](https://react-hotkeys-hook.vercel.app/docs/intro) that makes it more performant and avoids unnecessary re-renders.
|
||||
|
||||
We also create a Recoil state to handle the hotkey scope state and make it available everywhere in the application.
|
||||
@ -289,3 +289,5 @@ An ESLint rule, `@typescript-eslint/consistent-type-imports`, enforces the no-ty
|
||||
Please note that this rule specifically addresses rare edge cases where unintentional type imports occur. TypeScript itself discourages this practice, as mentioned in the [TypeScript 3.8 release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html). In most situations, you should not need to use type-only imports.
|
||||
|
||||
To ensure your code complies with this rule, make sure to run ESLint as part of your development workflow.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -61,4 +61,6 @@ It's part of our recommended extensions.
|
||||
## Collaboration
|
||||
|
||||
1. **Using Comments:** You are welcome to use the comment feature by clicking on the bubble icon in the left part of the toolbar.
|
||||
2. **Cursor chat:** A nice feature of Figma is the Cursor chat. Just press `;` on Mac and `/` on Windows to send a message if you see someone else using Figma as the same time as you.
|
||||
2. **Cursor chat:** A nice feature of Figma is the Cursor chat. Just press `;` on Mac and `/` on Windows to send a message if you see someone else using Figma as the same time as you.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -231,3 +231,5 @@ This should work out of the box with the eslint extension installed. If this doe
|
||||
#### Docker container build
|
||||
|
||||
To successfully build Docker images, ensure that your system has a minimum of 2GB of memory available. For users of Docker Desktop, please verify that you've allocated sufficient resources to Docker within the application's settings.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -50,7 +50,7 @@ This uses the prebuilt images found on [docker hub](https://hub.docker.com/r/twe
|
||||
#### Environment Variables
|
||||
|
||||
- Is set in respective tf-files
|
||||
- See docs [Setup Environment Variables](https://docs.twenty.com/start/self-hosting/) for usage
|
||||
- See docs [Setup Environment Variables](https://twenty.com/developers/section/self-hosting/self-hosting-var) for usage
|
||||
- After deployment you could can set `IS_SIGN_UP_DISABLED=true` (and run `terraform plan/apply` again) to disable new workspaces from being created
|
||||
|
||||
#### Security and networking
|
||||
@ -325,7 +325,8 @@ resource "azurerm_container_app" "twenty_server" {
|
||||
}
|
||||
env {
|
||||
name = "PG_DATABASE_URL"
|
||||
value = "postgres://${local.db_user}:${local.db_password}@${local.db_app_name}:5432/default"
|
||||
value = "postgres://${local.db_user}:
|
||||
${local.db_password}@${local.db_app_name}:5432/default"
|
||||
}
|
||||
env {
|
||||
name = "FRONT_BASE_URL"
|
||||
@ -434,3 +435,5 @@ resource "azurerm_container_app" "twenty_db" {
|
||||
## Others
|
||||
|
||||
Please feel free to Open a PR to add more Cloud Provider options.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -50,3 +50,5 @@ Complete step three and four with:
|
||||
#### Persistence
|
||||
|
||||
By default the docker-compose will create volumes for the Database and local storage of the Server. Note that the containers will not persist data if your server is not configured to be stateful (for example Heroku). You probably want to configure a special stateful resource for this purpose.
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -6,6 +6,15 @@ image: /images/user-guide/table-views/table.png
|
||||
|
||||
import OptionTable from '@site/src/theme/OptionTable'
|
||||
|
||||
# Setup Messaging & Calendar sync
|
||||
|
||||
Twenty offers integrations with Gmail and Google Calendar. To enable these features, you need to connect to register the following recurring jobs:
|
||||
```
|
||||
# from your worker container
|
||||
yarn command:prod cron:messaging:messages-import
|
||||
yarn command:prod cron:messaging:message-list-fetch
|
||||
```
|
||||
|
||||
# Setup Environment Variables
|
||||
|
||||
## Frontend
|
||||
@ -96,9 +105,9 @@ import OptionTable from '@site/src/theme/OptionTable'
|
||||
|
||||
You will need to provision an [App Password](https://support.google.com/accounts/answer/185833).
|
||||
- EMAIL_SMTP_HOST=smtp.gmail.com
|
||||
- EMAIL_SERVER_PORT=465
|
||||
- EMAIL_SERVER_USER=gmail_email_address
|
||||
- EMAIL_SERVER_PASSWORD='gmail_app_password'
|
||||
- EMAIL_SMTP_PORT=465
|
||||
- EMAIL_SMTP_USER=gmail_email_address
|
||||
- EMAIL_SMTP_PASSWORD='gmail_app_password'
|
||||
|
||||
</ArticleTab>
|
||||
|
||||
@ -106,9 +115,9 @@ import OptionTable from '@site/src/theme/OptionTable'
|
||||
|
||||
Keep in mind that if you have 2FA enabled, you will need to provision an [App Password](https://support.microsoft.com/en-us/account-billing/manage-app-passwords-for-two-step-verification-d6dc8c6d-4bf7-4851-ad95-6d07799387e9).
|
||||
- EMAIL_SMTP_HOST=smtp.office365.com
|
||||
- EMAIL_SERVER_PORT=587
|
||||
- EMAIL_SERVER_USER=office365_email_address
|
||||
- EMAIL_SERVER_PASSWORD='office365_password'
|
||||
- EMAIL_SMTP_PORT=587
|
||||
- EMAIL_SMTP_USER=office365_email_address
|
||||
- EMAIL_SMTP_PASSWORD='office365_password'
|
||||
|
||||
</ArticleTab>
|
||||
|
||||
@ -118,8 +127,8 @@ import OptionTable from '@site/src/theme/OptionTable'
|
||||
- Run the smtp4dev image: `docker run --rm -it -p 8090:80 -p 2525:25 rnwood/smtp4dev`
|
||||
- Access the smtp4dev ui here: [http://localhost:8090](http://localhost:8090)
|
||||
- Set the following env variables:
|
||||
- EMAIL_SERVER_HOST=localhost
|
||||
- EMAIL_SERVER_PORT=2525
|
||||
- EMAIL_SMTP_HOST=localhost
|
||||
- EMAIL_SMTP_PORT=2525
|
||||
|
||||
</ArticleTab>
|
||||
|
||||
@ -198,3 +207,5 @@ import OptionTable from '@site/src/theme/OptionTable'
|
||||
['CAPTCHA_SITE_KEY', '', 'The captcha site key'],
|
||||
['CAPTCHA_SECRET_KEY', '', 'The captcha secret key'],
|
||||
]}></ArticleTable>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -80,3 +80,5 @@ export const MyComponent = () => {
|
||||
</ArticleTab>
|
||||
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -60,4 +60,6 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
|
||||
</ArticleTabs>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -135,4 +135,6 @@ export const MyComponent = () => {
|
||||
]} />
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -77,4 +77,6 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
|
||||
</ArticleTabs>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -12,3 +12,4 @@ export const MyComponent = () => {
|
||||
return <SoonPill />;
|
||||
};`} />
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -37,3 +37,5 @@ export const MyComponent = () => {
|
||||
</ArticleTab>
|
||||
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
|
||||
@ -27,3 +27,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -468,3 +468,5 @@ export const MyComponent = () => {
|
||||
</ArticleTab>
|
||||
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -40,3 +40,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -64,3 +64,5 @@ export const MyComponent = () => {
|
||||
</ArticleTab>
|
||||
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -51,3 +51,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -36,3 +36,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -100,3 +100,5 @@ export const MyComponent = () => {
|
||||
</ArticleTab>
|
||||
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -50,3 +50,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -208,3 +208,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -32,3 +32,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -36,3 +36,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -161,3 +161,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -450,3 +450,5 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -45,4 +45,6 @@ export const MyComponent = () => {
|
||||
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -31,4 +31,6 @@ export const MyComponent = () => {
|
||||
|
||||
|
||||
</ArticleTab>
|
||||
</ArticleTabs>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -68,4 +68,6 @@ export const MyComponent = () => {
|
||||
|
||||
</ArticleTab>
|
||||
|
||||
</ArticleTabs>
|
||||
</ArticleTabs>
|
||||
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -84,4 +84,4 @@ For instance, a webhook can alert your system in real-time when someone creates
|
||||
1. In Developers, find your webhook.
|
||||
2. Click on your webhook and press **Delete** to remove it. A confirmation popup will appear to confirm.
|
||||
|
||||
<ArticleEditContent articleTitle="api-webhooks.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -50,4 +50,4 @@ Contact auto-creation is a handy built-in feature. This default feature automati
|
||||
|
||||
Soon, you will have the capability to send emails, view attachments, and request access to email content that you're not allowed to read.
|
||||
|
||||
<ArticleEditContent articleTitle="emails.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -43,4 +43,4 @@ Sync Twenty with 3000+ apps using <ArticleLink href="https://zapier.com/apps/twe
|
||||
|
||||
You can now continue creating your automation!
|
||||
|
||||
<ArticleEditContent articleTitle="integrations.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -67,4 +67,4 @@ To delete a note:
|
||||
|
||||
Please be aware that deleting a note is permanent and can't be undone.
|
||||
|
||||
<ArticleEditContent articleTitle="notes.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -112,4 +112,4 @@ To permanently remove a task:
|
||||
|
||||
Please note, deleting a task is permanent and can't be undone. Consider marking tasks as `Done` if there is a chance you will need to refer to them again.
|
||||
|
||||
<ArticleEditContent articleTitle="tasks.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -50,4 +50,4 @@ Post payment approval via Stripe, you're directed to create your workspace and u
|
||||
## Support
|
||||
For queries or help, connect with the dedicated support team at [contact@twenty.com](mailto:contact@twenty.com) or send a message on <ArticleLink href="https://discord.gg/cx5n4Jzs57">Discord</ArticleLink>
|
||||
|
||||
<ArticleEditContent articleTitle="create-workspace.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -68,4 +68,4 @@ And Open-source is the bedrock of our approach, ensuring that Twenty evolves wit
|
||||
|
||||
<ArticleLink href="https://app.twenty.com">Register here</ArticleLink> or <ArticleLink href="https://github.com/twentyhq/twenty">become a contributor on GitHub</ArticleLink>.
|
||||
|
||||
<ArticleEditContent articleTitle="what-is-twenty.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -86,4 +86,4 @@ And, voila! You've deactivated a field. But what does this imply for your CRM op
|
||||
|
||||
You can reactivate Standard and Custom Fields or have the option to permanently delete them.
|
||||
|
||||
<ArticleEditContent articleTitle="fields.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -43,4 +43,4 @@ To export data from an object:
|
||||
</div>
|
||||
<script src="https://player.vimeo.com/api/player.js"></script>
|
||||
|
||||
<ArticleEditContent articleTitle="import-export-data.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -80,4 +80,4 @@ You can also hide all the fields, and get an overview of all the opportunities a
|
||||
|
||||
<img src="/images/user-guide/kanban-views/compact-view.png"style={{width:'100%'}}/>
|
||||
|
||||
<ArticleEditContent articleTitle="kanban-views.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -41,7 +41,7 @@ To create a new custom object:
|
||||
<div style={{padding:'71.24% 0 0 0', position:'relative', margin: '32px 0px 0px'}}>
|
||||
<iframe
|
||||
src="https://player.vimeo.com/video/926288174?autoplay=1&loop=1&autopause=0&background=1&app_id=58479"
|
||||
frameborder="0"
|
||||
frameBorder="0"
|
||||
allow="autoplay; fullscreen; picture-in-picture; clipboard-write"
|
||||
style={{
|
||||
position:'absolute',
|
||||
@ -62,7 +62,7 @@ To create a new custom object:
|
||||
<div style={{padding:'71.24% 0 0 0', position:'relative', margin: '32px 0px 0px'}}>
|
||||
<iframe
|
||||
src="https://player.vimeo.com/video/926293493?autoplay=1&loop=1&autopause=0&background=1&app_id=58479"
|
||||
frameborder="0"
|
||||
frameBorder="0"
|
||||
allow="autoplay; fullscreen; picture-in-picture; clipboard-write"
|
||||
style={{
|
||||
position:'absolute',
|
||||
@ -82,4 +82,4 @@ To create a new custom object:
|
||||
|
||||
<img src="/images/user-guide/objects/customize-fields.png"style={{width:'100%'}}/>
|
||||
|
||||
<ArticleEditContent articleTitle="objects.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -70,4 +70,4 @@ To create a custom field, click the **+** button at the right end of the table c
|
||||
|
||||
You can also do it by navigating to **Settings** > **Data Model** > **People**. Click on **Add Field**. Choose a field name and type. The new field will be available in the app.
|
||||
|
||||
<ArticleEditContent articleTitle="table-views.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -176,4 +176,4 @@ You can rearrange fields by clicking their field column header and then press **
|
||||
|
||||
To open a record, click on the name in the first column. This action will open the corresponding Record page.
|
||||
|
||||
<ArticleEditContent articleTitle="views-sort-filter.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -54,4 +54,4 @@ If you have any question, for example on how to contribute, join the community o
|
||||
<br/>
|
||||
Thank you for contributing to Twenty ❤️
|
||||
|
||||
<ArticleEditContent articleTitle="github.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -43,4 +43,4 @@ Integration are built-in tools that allow to link Twenty with other software or
|
||||
## User Profile
|
||||
A User Profile is the information and settings specific to a workspace member in Twenty.
|
||||
|
||||
<ArticleEditContent articleTitle="glossary.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
@ -89,4 +89,4 @@ You can add records to your favorites for quick access. To do so, expand the rec
|
||||
|
||||
<img src="/images/user-guide/tips/favorites.png" style={{width:'100%', maxWidth:'800px'}}/>
|
||||
|
||||
<ArticleEditContent articleTitle="tips.mdx"></ArticleEditContent>
|
||||
<ArticleEditContent></ArticleEditContent>
|
||||
Reference in New Issue
Block a user