Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 70e22ce10b chore: improve monitoring for fix: handle stale API key role cache gracefully in
**Monitoring fix in `permission-graphql-api-exception-handler.util.ts`:** Moved `API_KEY_ROLE_NOT_FOUND` and `APPLICATION_ROLE_NOT_FOUND` from the raw re-throw group (line 74) to a new `ForbiddenError` mapping. This ensures these exceptions are converted to proper GraphQL errors before reaching the client, matching the pattern used for similar auth/permission errors (e.g., `PERMISSION_DENIED`, `NO_AUTHENTICATION_CONTEXT`).

Previously, these two codes fell through to `throw error` which propagated the raw `PermissionsException` up the stack, causing Sentry to capture it as an unhandled error. Now they're wrapped as `ForbiddenError` GraphQL responses, which:
1. Return a clean, structured error to the API consumer
2. Prevent unnecessary Sentry noise since `ForbiddenError` is a handled GraphQL error type
3. Are consistent with how `API_KEY_NO_ROLE_ASSIGNED` is handled in `api-key-graphql-api-exception-handler.util.ts`
2026-04-06 18:25:37 +00:00
Sonarly Claude Code 431b197d05 fix: handle stale API key role cache gracefully in permissions check
https://sonarly.com/issue/22241?type=bug

An API key used to call the metadata API (createOneField) has a cached role assignment pointing to a role that no longer exists in the database, causing a permission check failure.

Fix: **Code fix in `permissions.service.ts`:** When `roleRepository.findOne` returns null for a cached API key role, the code now invalidates and recomputes the `apiKeyRoleMap` cache, then retries the role lookup once. This handles the stale cache scenario where a role was deleted but the cache still contains the old roleId→roleTarget mapping. After the retry, if the role is still not found (meaning the API key genuinely has no valid role), the original `API_KEY_ROLE_NOT_FOUND` exception is thrown.

The fix uses `let` instead of `const` for the `role` variable to allow reassignment after the cache refresh. The retry path calls `getRoleIdForApiKeyId` again after cache invalidation, which will either return a fresh roleId or throw `API_KEY_NO_ROLE_ASSIGNED` if the roleTarget was also cleaned up.
2026-04-06 18:25:37 +00:00
aec43da1e2 i18n - translations (#19355)
Created by Github action

---------

Co-authored-by: github-actions <[email protected]>
2026-04-06 12:13:17 +02:00
646edec104 i18n - translations (#19354)
Created by Github action

---------

Co-authored-by: github-actions <[email protected]>
2026-04-06 12:08:11 +02:00
Félix MalfaitGitHubClaude Opus 4.6claude[bot] <41898282+claude[bot]@users.noreply.github.com>
ea572975d8 feat: generic web search driver abstraction with Exa support and billing (#19341)
## Summary

- Introduces a pluggable `WebSearchDriver` abstraction (interface,
factory, service, module) so web search is no longer tied to native
provider tools (Anthropic/OpenAI)
- **Exa** is the first driver implementation with support for
category-filtered search (company, people, news, research paper, etc.) —
particularly useful for CRM workflows
- Per-query billing for both Exa ($0.007/query) and native provider
surcharges ($0.01/query for Anthropic/OpenAI) via the existing
`USAGE_RECORDED` pipeline
- New config variables: `WEB_SEARCH_DRIVER` (EXA/DISABLED),
`EXA_API_KEY`, `WEB_SEARCH_PREFER_NATIVE` (default false — prefers Exa
over native when both available)
- `WEB_SEARCH` operation type added for usage tracking and Stripe
metering

### Architecture

```
WebSearchDriver (interface)
├── ExaDriver          — Exa neural search with category support
└── DisabledDriver     — throws when search is disabled

WebSearchDriverFactory (extends DriverFactoryBase)
└── creates driver based on WEB_SEARCH_DRIVER config

WebSearchService (facade)
├── search(query, options?, billingContext?)
├── isEnabled()
└── emits USAGE_RECORDED events per query

WebSearchTool (Tool implementation)
└── registered in ActionToolProvider, available via tool catalog
```

### Native search billing gap fixed

Anthropic and OpenAI both charge $0.01/search on top of token costs. The
token costs were already billed, but the per-call surcharge was not.
Added `countNativeWebSearchCallsFromSteps` utility +
`billNativeWebSearchUsage` to `AiBillingService`, wired into both chat
and workflow agent paths.

## Test plan

- [ ] Set `WEB_SEARCH_DRIVER=EXA` + `EXA_API_KEY=...` and verify AI chat
can search the web
- [ ] Verify category parameter works (ask about a specific
company/person)
- [ ] Set `WEB_SEARCH_DRIVER=DISABLED` and verify search tool is not
exposed
- [ ] Set `WEB_SEARCH_PREFER_NATIVE=true` with Anthropic model and
verify native search is used
- [ ] Verify usage events are emitted in ClickHouse for both Exa and
native search paths
- [ ] Verify existing billing tests pass (`npx jest
ai-billing.service.spec.ts`)


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-04-06 12:02:46 +02:00
8acfacc69c Add email thread widget and message thread record page layout (#19351)
## Summary
- Move email thread display from side panel to a dedicated record page
with a new `EMAIL_THREAD` widget type
- Add message thread as a standard object with page layout, subject
field, and backfill command
- Add reply-to-email command menu item for message thread records
- Remove old side panel message thread components in favor of the new
widget-based approach

## Type fixes
- Add `EMAIL_THREAD` to `WidgetConfigurationType`, `WidgetType`, and all
configuration/validator maps
- Create `EmailThreadConfigurationDTO` and shared
`EmailThreadConfiguration` type
- Register EMAIL_THREAD in widget type validators, configuration
resolvers, and standard widget mappings

## Test plan
- [ ] Verify message thread record pages render with the email thread
widget
- [ ] Verify email thread preview navigates to the record page instead
of opening side panel
- [ ] Verify reply-to-email command appears for message thread records
- [ ] Verify typecheck passes for both twenty-front and twenty-server
- [ ] Run existing test suites to check for regressions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-04-06 12:02:04 +02:00
Thomas des FrancsandGitHub 4aa1d71b12 few website improvements (#19353)
## Summary
- refine the home so it scrolls after home illustration scroll right
- Added few tweaks to pricing hero
2026-04-06 09:52:40 +00:00
BOHEUSandGitHub 7bf309ba73 Update last interaction app (#19332)
Rewrite to 0.8.0 SDK
2026-04-06 09:22:24 +00:00
8d61bb9ae6 Migrate messageFolder parentFolderId from UUID to externalId (#19348)
This PR migrates `messageFolder`.`parentFolderId` from an internal
`UUID` reference to external provider id.
Eliminates unnecessary lookup and complexity

---------

Co-authored-by: Charles Bochet <[email protected]>
2026-04-06 09:12:44 +00:00
0d44d7c6d7 i18n - translations (#19352)
Created by Github action

---------

Co-authored-by: github-actions <[email protected]>
2026-04-06 10:28:59 +02:00
neo773GitHubmartmullgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github-actionsClaude Sonnet 4.6Charles Bochet
d3f0162cf5 Remove connected account feature flag (#19286)
Co-authored-by: martmull <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions <[email protected]>
Co-authored-by: Claude Sonnet 4.6 <[email protected]>
Co-authored-by: Charles Bochet <[email protected]>
2026-04-06 08:13:41 +00:00
478 changed files with 11047 additions and 9393 deletions
@@ -0,0 +1,38 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn
# codegen
generated
# testing
/coverage
# dev
/dist/
.twenty
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# typescript
*.tsbuildinfo
*.d.ts
@@ -0,0 +1 @@
24.5.0
@@ -0,0 +1,19 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript"],
"categories": {
"correctness": "off"
},
"ignorePatterns": ["node_modules", "dist"],
"rules": {
"no-unused-vars": "off",
"typescript/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_"
}
],
"typescript/no-explicit-any": "off"
}
}
@@ -2,22 +2,18 @@
Updates Last interaction and Interaction status fields based on last email date
## Requirements
- an `apiKey` - go to Settings > API & Webhooks to generate one
## Setup
1. Add and synchronize app
Add and synchronize app
```bash
cd packages/twenty-apps/community/last-email-interaction
yarn auth
yarn sync
yarn twenty remote add
yarn twenty install
```
2. Go to Settings > Integrations > Last email interaction > Settings and add required variables
## Flow
- Checks if fields are created, if not, creates them on fly
- Extracts the datetime of message and calculates the last interaction status
- Fetches all users and companies connected to them and updates their Last interaction and Interaction status fields
- Extracts the datetime of fetched message and calculates the last interaction status
- Fetches all users and companies connected to the message and updates their Last interaction and Interaction status fields
## Todo:
- update app with generated Twenty object once extending objects is possible
## Notes
- Upon install, creates fields to Person and Company objects
- Every day at midnight app goes through all companies and people records and updates their Interaction status based on Last interaction date
@@ -1,23 +0,0 @@
import { type ApplicationConfig } from 'twenty-sdk';
const config: ApplicationConfig = {
universalIdentifier: '718ed9ab-53fc-49c8-8deb-0cff78ecf0d2',
displayName: 'Last email interaction',
description:
'Updates Last interaction and Interaction status fields based on last received email',
icon: "IconMailFast",
applicationVariables: {
TWENTY_API_KEY: {
universalIdentifier: 'aae3f523-4c1f-4805-b3ee-afeb676c381e',
isSecret: true,
description: 'Required to send requests to Twenty',
},
TWENTY_API_URL: {
universalIdentifier: '6d19bb04-45bb-46aa-a4e5-4a2682c7b19d',
isSecret: false,
description: 'Optional, defaults to cloud API URL',
},
},
};
export default config;
@@ -9,19 +9,23 @@
},
"packageManager": "[email protected]",
"dependencies": {
"axios": "^1.12.2",
"twenty-sdk": "0.2.4"
},
"devDependencies": {
"@types/node": "^24.7.2"
"axios": "1.14.0",
"twenty-sdk": "0.8.0"
},
"scripts": {
"auth": "twenty auth login",
"dev": "twenty app dev",
"sync": "twenty app sync",
"uninstall": "twenty app uninstall",
"logs": "twenty app logs",
"create-entity": "twenty app add",
"help": "twenty --help"
"twenty": "twenty",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json .",
"test": "vitest run",
"test:watch": "vitest"
},
"devDependencies": {
"@types/node": "^24.7.2",
"@types/react": "^18.2.0",
"oxlint": "^0.16.0",
"react": "^18.2.0",
"typescript": "^5.9.3",
"vite-tsconfig-paths": "^4.2.1",
"vitest": "^3.1.1"
}
}
@@ -0,0 +1,10 @@
import { defineApplication } from 'twenty-sdk';
export default defineApplication({
universalIdentifier: '718ed9ab-53fc-49c8-8deb-0cff78ecf0d2',
displayName: 'Last email interaction',
description:
'Updates Last interaction and Interaction status fields based on last received email',
icon: "IconMailFast",
defaultRoleUniversalIdentifier: '7a66af97-5056-45b2-96a9-c89f0fd181d1',
});
@@ -0,0 +1,41 @@
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk';
export default defineField({
universalIdentifier: '9378751e-c23b-4e84-887d-2905cb8359b4',
name: 'interactionStatus',
label: 'Interaction status',
type: FieldType.SELECT,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
description: 'Indicates the health of relation',
options: [
{
id: '39d54a6b-5a0e-4209-9a59-2a2d7b8c462b',
color: 'green',
label: 'Recent',
value: 'RECENT',
position: 1,
},
{
id: '7377d6c5-a75c-453e-a1a1-63fb9cba4e26',
color: 'yellow',
label: 'Active',
value: 'ACTIVE',
position: 2,
},
{
id: 'a8b99246-237f-4715-b21f-94a3ae14994e',
color: 'sky',
label: 'Cooling',
value: 'COOLING',
position: 3,
},
{
id: '1f05d528-eaab-4639-aba1-328050a87220',
color: 'gray',
label: 'Dormant',
value: 'DORMANT',
position: 4,
},
],
});
@@ -0,0 +1,14 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk';
export default defineField({
universalIdentifier: '2f195c4c-1db1-4bbe-80b6-25c2f63168b0',
name: 'lastInteraction',
label: 'Last interaction',
type: FieldType.DATE_TIME,
objectUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
description: 'Date when the last interaction happened',
});
@@ -0,0 +1,41 @@
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk';
export default defineField({
universalIdentifier: 'fa342e26-9742-4db8-85b4-4d78ba18482f',
name: 'interactionStatus',
label: 'Interaction status',
type: FieldType.SELECT,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
description: 'Indicates the health of relation',
options: [
{
id: '1dfbfa99-35fb-43af-8c14-74e682a8121b',
color: 'green',
label: 'Recent',
value: 'RECENT',
position: 1,
},
{
id: '955788e8-6d64-45ba-80ea-a1a5446a0ae7',
color: 'yellow',
label: 'Active',
value: 'ACTIVE',
position: 2,
},
{
id: '7b84ca72-fac5-4c6d-ab08-b148e4b3efdf',
color: 'sky',
label: 'Cooling',
value: 'COOLING',
position: 3,
},
{
id: '04dea3e5-ec26-41cf-b23f-37abab67827a',
color: 'gray',
label: 'Dormant',
value: 'DORMANT',
position: 4,
},
],
});
@@ -0,0 +1,14 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk';
export default defineField({
universalIdentifier: 'bec14de7-6683-4784-91ba-62d83b5f30f7',
name: 'lastInteraction',
label: 'Last interaction',
type: FieldType.DATE_TIME,
objectUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
description: 'Date when the last interaction happened',
});
@@ -1,270 +0,0 @@
import axios from 'axios';
import { type FunctionConfig } from 'twenty-sdk';
const TWENTY_API_KEY = process.env.TWENTY_API_KEY ?? '';
const TWENTY_URL =
process.env.TWENTY_API_URL !== '' && process.env.TWENTY_API_URL !== undefined
? `${process.env.TWENTY_API_URL}/rest`
: 'https://api.twenty.com/rest';
const create_last_interaction = (id: string) => {
return {
method: 'POST',
url: `${TWENTY_URL}/metadata/fields`,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${TWENTY_API_KEY}`,
},
data: {
type: 'DATE_TIME',
objectMetadataId: `${id}`,
name: 'lastInteraction',
label: 'Last interaction',
description: 'Date when the last interaction happened',
icon: 'IconCalendarClock',
defaultValue: null,
isNullable: true,
settings: {},
},
};
};
const create_interaction_status = (id: string) => {
return {
method: 'POST',
url: `${TWENTY_URL}/metadata/fields`,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${TWENTY_API_KEY}`,
},
data: {
type: 'SELECT',
objectMetadataId: `${id}`,
name: 'interactionStatus',
label: 'Interaction status',
description: 'Indicates the health of relation',
icon: 'IconProgress',
defaultValue: null,
isNullable: true,
settings: {},
options: [
{
color: 'green',
label: 'Recent',
value: 'RECENT',
position: 1,
},
{
color: 'yellow',
label: 'Active',
value: 'ACTIVE',
position: 2,
},
{
color: 'sky',
label: 'Cooling',
value: 'COOLING',
position: 3,
},
{
color: 'gray',
label: 'Dormant',
value: 'DORMANT',
position: 4,
},
],
},
};
};
const calculateStatus = (date: string) => {
const day = 1000 * 60 * 60 * 24;
const now = Date.now();
const messageDate = Date.parse(date);
const deltaTime = now - messageDate;
return deltaTime < 7 * day
? 'RECENT'
: deltaTime < 30 * day
? 'ACTIVE'
: deltaTime < 90 * day
? 'COOLING'
: 'DORMANT';
};
const updateInteractionStatus = async (objectName: string, id: string, messageDate: string, status: string) => {
const options = {
method: 'PATCH',
url: `${TWENTY_URL}/${objectName}/${id}`,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${TWENTY_API_KEY}`,
},
data: {
lastInteraction: messageDate,
interactionStatus: status
}
};
try {
const response = await axios.request(options);
if (response.status === 200) {
console.log('Successfully updated company last interaction field');
}
} catch (error) {
if (axios.isAxiosError(error)) {
throw error;
}
throw error;
}
}
const fetchRelatedCompanyId = async (id: string) => {
const options = {
method: 'GET',
url: `${TWENTY_URL}/people/${id}`,
headers: {
Authorization: `Bearer ${TWENTY_API_KEY}`,
},
};
try {
const req = await axios.request(options);
if (req.status === 200 && req.data.person.companyId !== null && req.data.person.companyId !== undefined) {
return req.data.person.companyId;
}
} catch (error) {
if (axios.isAxiosError(error)) {
throw error;
}
throw error;
}
}
export const main = async (params: {
properties: Record<string, any>;
recordId: string;
userId: string;
}): Promise<object | undefined> => {
if (TWENTY_API_KEY === '') {
console.log("Function exited as API key or URL hasn't been set properly");
return {};
}
const { properties, recordId } = params;
// Check if fields are created
const options = {
method: 'GET',
url: `${TWENTY_URL}/metadata/objects`,
headers: {
Authorization: `Bearer ${TWENTY_API_KEY}`,
},
};
try {
const response = await axios.request(options);
const objects = response.data.data.objects;
const company_object = objects.find(
(object: any) => object.nameSingular === 'company',
);
const company_last_interaction = company_object.fields.find(
(field: any) => field.name === 'lastInteraction',
);
const company_interaction_status = company_object.fields.find(
(field: any) => field.name === 'interactionStatus',
);
const person_object = objects.find(
(object: any) => object.nameSingular === 'person',
);
const person_last_interaction = person_object.fields.find(
(field: any) => field.name === 'lastInteraction',
);
const person_interaction_status = person_object.fields.find(
(field: any) => field.name === 'interactionStatus',
);
// If not, create them
if (company_last_interaction === undefined) {
const response2 = await axios.request(
create_last_interaction(company_object.id),
);
if (response2.status === 201) {
console.log('Successfully created company last interaction field');
}
}
if (company_interaction_status === undefined) {
const response2 = await axios.request(
create_interaction_status(company_object.id),
);
if (response2.status === 201) {
console.log('Successfully created company interaction status field');
}
}
if (person_last_interaction === undefined) {
const response2 = await axios.request(
create_last_interaction(person_object.id),
);
if (response2.status === 201) {
console.log('Successfully created person last interaction field');
}
}
if (person_interaction_status === undefined) {
const response2 = await axios.request(
create_interaction_status(person_object.id),
);
if (response2.status === 201) {
console.log('Successfully created person interaction status field');
}
}
// Extract the timestamp of message
const messageDate = properties.after.receivedAt;
const interactionStatus = calculateStatus(messageDate);
// Get the details of person and related company
const messageOptions = {
method: 'GET',
url: `${TWENTY_URL}/messages/${recordId}?depth=1`,
headers: {
Authorization: `Bearer ${TWENTY_API_KEY}`,
},
};
const messageDetails = await axios.request(messageOptions);
const peopleIds: string[] = [];
for (const participant of messageDetails.data.messages
.messageParticipants) {
peopleIds.push(participant.personId);
}
const companiesIds = [];
for (const id of peopleIds) {
companiesIds.push(await fetchRelatedCompanyId(id));
}
// Update the field value depending on the timestamp
for (const id of peopleIds) {
await updateInteractionStatus("people", id, messageDate, interactionStatus);
}
for (const id of companiesIds) {
await updateInteractionStatus("companies", id, messageDate, interactionStatus);
}
} catch (error) {
if (axios.isAxiosError(error)) {
console.error(error.message);
return {};
}
console.error(error);
return {};
}
};
export const config: FunctionConfig = {
universalIdentifier: '683966a0-b60a-424e-86b1-7448c9191bde',
name: 'test',
triggers: [
{
universalIdentifier: 'f4f1e127-87f0-4dcf-99fe-8061adf5cbe6',
type: 'databaseEvent',
eventName: 'message.created',
},
{
universalIdentifier: '4c17878f-b6b3-4d0a-8de6-967b1cb55002',
type: 'databaseEvent',
eventName: 'message.updated',
},
],
};
@@ -0,0 +1,126 @@
import { defineLogicFunction } from 'twenty-sdk';
import { CoreApiClient } from 'twenty-client-sdk/core';
import { calculateStatus } from '../shared/calculate-status';
const fetchAllPeople = async () => {
const client = new CoreApiClient();
const result = await client.query({
people: {
__args: {
filter: {
/*
lastInteraction: {
is: 'NOT_NULL',
},
*/
},
},
edges: {
node: {
id: true,
lastInteraction: true,
interactionStatus: true,
},
},
},
});
if (!result.people) {
throw new Error('Could not find any people');
}
return result.people.edges;
}
const fetchAllCompanies = async () => {
const client = new CoreApiClient();
const result = await client.query({
companies: {
__args: {
filter: {
/* how to fetch fields added in fields folder?
lastInteraction: {
is: 'NOT_NULL',
},
*/
},
},
edges: {
node: {
id: true,
lastInteraction: true,
interactionStatus: true,
},
},
},
});
if (!result.companies) {
throw new Error('Could not find any companies');
}
return result.companies.edges;
}
const updateCompany = async (
companyId: string,
updateData: Record<string, string>,
) => {
const client = new CoreApiClient();
const result = await client.mutation({
updateCompany: {
__args: {
id: companyId,
data: updateData,
},
id: true,
},
});
if (!result.updateCompany) {
throw new Error(`Failed to update company ${companyId}`);
}
};
const updatePerson = async (
personId: string,
updateData: Record<string, string>,
) => {
const client = new CoreApiClient();
const result = await client.mutation({
updatePerson: {
__args: {
id: personId,
data: updateData,
},
id: true,
},
});
if (!result.updatePerson) {
throw new Error(`Failed to update person ${personId}`);
}
};
const handler = async () => {
const people = await fetchAllPeople();
for (const person of people) {
const interactionStatus = calculateStatus(person.node.lastInteraction as string);
if (interactionStatus !== person.node.interactionStatus) {
await updatePerson(person.node.id, {interactionStatus: interactionStatus});
}
}
const companies = await fetchAllCompanies();
for (const company of companies) {
const interactionStatus = calculateStatus(company.node.lastInteraction as string);
if (interactionStatus !== company.node.interactionStatus) {
await updateCompany(company.node.id, {interactionStatus: interactionStatus});
}
}
};
export default defineLogicFunction({
universalIdentifier: 'c79f1f30-f369-4264-9e5b-c183577bc709',
name: 'on-cron-job',
description:
'Runs daily at midnight and updates all companies and people with correct interaction status',
timeoutSeconds: 5,
handler,
cronTriggerSettings: {
pattern: '0 0 * * *', // runs daily at midnight
},
});
@@ -0,0 +1,143 @@
import {
DatabaseEventPayload,
defineLogicFunction,
ObjectRecordCreateEvent,
} from 'twenty-sdk';
import { CoreApiClient } from 'twenty-client-sdk/core';
import { calculateStatus } from '../shared/calculate-status';
const fetchMessageParticipants = async (messageId: string) => {
const client = new CoreApiClient();
const result = await client.query({
messageParticipants: {
__args: {
filter: {
messageId: {
eq: messageId,
},
},
},
edges: {
node: {
personId: true,
},
},
},
});
let people: string[] = [];
if (result.messageParticipants === undefined) {
return people;
}
for (const person of result.messageParticipants.edges) {
if (person.node.personId !== undefined) {
people.push(person.node.personId);
}
}
return people;
};
const fetchRelatedCompany = async (personId: string) => {
const client = new CoreApiClient();
const result = await client.query({
people: {
__args: {
filter: {
id: {
eq: personId,
},
},
},
edges: {
node: {
company: {
id: true,
},
},
},
},
});
if (
result.people === undefined ||
result.people.edges[0].node.company === undefined
) {
throw new Error(`Failed to fetch related company of person ${personId}`);
}
return result.people.edges[0].node.company.id;
};
const updateCompany = async (
companyId: string,
updateData: Record<string, string>,
) => {
const client = new CoreApiClient();
const result = await client.mutation({
updateCompany: {
__args: {
id: companyId,
data: updateData,
},
id: true,
},
});
if (!result.updateCompany) {
throw new Error(`Failed to update company ${companyId}`);
}
};
const updatePerson = async (
personId: string,
updateData: Record<string, string>,
) => {
const client = new CoreApiClient();
const result = await client.mutation({
updatePerson: {
__args: {
id: personId,
data: updateData,
},
id: true,
},
});
if (!result.updatePerson) {
throw new Error(`Failed to update person ${personId}`);
}
};
type Message = {
receivedAt: string;
};
type MessageCreatedEvent = DatabaseEventPayload<
ObjectRecordCreateEvent<Message>
>;
const handler = async (
event: MessageCreatedEvent,
): Promise<object | undefined> => {
const { properties, recordId } = event;
const interactionStatus = calculateStatus(properties.after.receivedAt);
const peopleIds: string[] = [];
peopleIds.push(...(await fetchMessageParticipants(recordId)));
const updateData = {
lastInteraction: properties.after.receivedAt,
interactionStatus: interactionStatus,
};
for (const person of peopleIds) {
const companyId = await fetchRelatedCompany(person);
await updatePerson(person, updateData);
await updateCompany(companyId, updateData);
}
return {};
};
export default defineLogicFunction({
universalIdentifier: '543432c2-6509-4ee9-90ec-15ffb4d7abfc',
name: 'on-message-created',
description: 'Triggered when new message is created',
timeoutSeconds: 5,
handler,
databaseEventTriggerSettings: {
eventName: 'message.created',
},
});
@@ -0,0 +1,143 @@
import {
DatabaseEventPayload,
defineLogicFunction,
ObjectRecordCreateEvent,
} from 'twenty-sdk';
import { CoreApiClient } from 'twenty-client-sdk/core';
import { calculateStatus } from '../shared/calculate-status';
const fetchMessageParticipants = async (messageId: string) => {
const client = new CoreApiClient();
const result = await client.query({
messageParticipants: {
__args: {
filter: {
messageId: {
eq: messageId,
},
},
},
edges: {
node: {
personId: true,
},
},
},
});
let people: string[] = [];
if (result.messageParticipants === undefined) {
return people;
}
for (const person of result.messageParticipants.edges) {
if (person.node.personId !== undefined) {
people.push(person.node.personId);
}
}
return people;
};
const fetchRelatedCompany = async (personId: string) => {
const client = new CoreApiClient();
const result = await client.query({
people: {
__args: {
filter: {
id: {
eq: personId,
},
},
},
edges: {
node: {
company: {
id: true,
},
},
},
},
});
if (
result.people === undefined ||
result.people.edges[0].node.company === undefined
) {
throw new Error(`Failed to fetch related company of person ${personId}`);
}
return result.people.edges[0].node.company.id;
};
const updateCompany = async (
companyId: string,
updateData: Record<string, string>,
) => {
const client = new CoreApiClient();
const result = await client.mutation({
updateCompany: {
__args: {
id: companyId,
data: updateData,
},
id: true,
},
});
if (!result.updateCompany) {
throw new Error(`Failed to update company ${companyId}`);
}
};
const updatePerson = async (
personId: string,
updateData: Record<string, string>,
) => {
const client = new CoreApiClient();
const result = await client.mutation({
updatePerson: {
__args: {
id: personId,
data: updateData,
},
id: true,
},
});
if (!result.updatePerson) {
throw new Error(`Failed to update person ${personId}`);
}
};
type Message = {
receivedAt: string;
};
type MessageCreatedEvent = DatabaseEventPayload<
ObjectRecordCreateEvent<Message>
>;
const handler = async (
event: MessageCreatedEvent,
): Promise<object | undefined> => {
const { properties, recordId } = event;
const interactionStatus = calculateStatus(properties.after.receivedAt);
const peopleIds: string[] = [];
peopleIds.push(...(await fetchMessageParticipants(recordId)));
const updateData = {
lastInteraction: properties.after.receivedAt,
interactionStatus: interactionStatus,
};
for (const person of peopleIds) {
const companyId = await fetchRelatedCompany(person);
await updatePerson(person, updateData);
await updateCompany(companyId, updateData);
}
return {};
};
export default defineLogicFunction({
universalIdentifier: '9bfcb3e4-9119-4b65-b6e9-d395d0764ce5',
name: 'on-message-updated',
description: 'Triggered when message is updated',
timeoutSeconds: 5,
handler,
databaseEventTriggerSettings: {
eventName: 'message.updated',
},
});
@@ -0,0 +1,13 @@
export const calculateStatus = (date: string) => {
const day = 1000 * 60 * 60 * 24;
const now = Date.now();
const messageDate = Date.parse(date);
const deltaTime = now - messageDate;
return deltaTime < 7 * day
? 'RECENT'
: deltaTime < 30 * day
? 'ACTIVE'
: deltaTime < 90 * day
? 'COOLING'
: 'DORMANT';
};
@@ -0,0 +1,17 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"composite": true,
"types": [
"vitest/globals"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx"
],
"exclude": [
"node_modules",
"dist"
]
}
File diff suppressed because it is too large Load Diff
@@ -921,6 +921,7 @@ enum WidgetType {
WORKFLOW_RUN
FRONT_COMPONENT
RECORD_TABLE
EMAIL_THREAD
}
union PageLayoutWidgetPosition = PageLayoutWidgetGridPosition | PageLayoutWidgetVerticalListPosition | PageLayoutWidgetCanvasPosition
@@ -948,7 +949,7 @@ type PageLayoutWidgetCanvasPosition {
layoutMode: PageLayoutTabLayoutMode!
}
union WidgetConfiguration = AggregateChartConfiguration | StandaloneRichTextConfiguration | PieChartConfiguration | LineChartConfiguration | IframeConfiguration | GaugeChartConfiguration | BarChartConfiguration | CalendarConfiguration | FrontComponentConfiguration | EmailsConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | NotesConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | RecordTableConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration
union WidgetConfiguration = AggregateChartConfiguration | StandaloneRichTextConfiguration | PieChartConfiguration | LineChartConfiguration | IframeConfiguration | GaugeChartConfiguration | BarChartConfiguration | CalendarConfiguration | FrontComponentConfiguration | EmailsConfiguration | EmailThreadConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | NotesConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | RecordTableConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration
type AggregateChartConfiguration {
configurationType: WidgetConfigurationType!
@@ -989,6 +990,7 @@ enum WidgetConfigurationType {
WORKFLOW_RUN
FRONT_COMPONENT
RECORD_TABLE
EMAIL_THREAD
}
type StandaloneRichTextConfiguration {
@@ -1154,6 +1156,10 @@ type EmailsConfiguration {
configurationType: WidgetConfigurationType!
}
type EmailThreadConfiguration {
configurationType: WidgetConfigurationType!
}
type FieldConfiguration {
configurationType: WidgetConfigurationType!
fieldMetadataId: String!
@@ -1733,7 +1739,6 @@ enum FeatureFlagKey {
IS_USAGE_ANALYTICS_ENABLED
IS_RICH_TEXT_V1_MIGRATED
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
IS_CONNECTED_ACCOUNT_MIGRATED
IS_RECORD_TABLE_WIDGET_ENABLED
IS_DATASOURCE_MIGRATED
}
@@ -2542,7 +2547,7 @@ type ConnectedImapSmtpCaldavAccount {
id: UUID!
handle: String!
provider: String!
accountOwnerId: UUID!
userWorkspaceId: UUID!
connectionParameters: ImapSmtpCaldavConnectionParameters
}
@@ -2633,6 +2638,7 @@ enum EngineComponentKey {
VIEW_PREVIOUS_AI_CHATS
TRIGGER_WORKFLOW_VERSION
FRONT_COMPONENT_RENDERER
REPLY_TO_EMAIL_THREAD
DELETE_SINGLE_RECORD
DELETE_MULTIPLE_RECORDS
RESTORE_SINGLE_RECORD
@@ -3013,7 +3019,7 @@ type MessageFolder {
name: String
isSentFolder: Boolean!
isSynced: Boolean!
parentFolderId: UUID
parentFolderId: String
externalId: String
pendingSyncAction: MessageFolderPendingSyncAction!
messageChannelId: UUID!
@@ -3370,6 +3376,7 @@ enum UsageOperationType {
AI_WORKFLOW_TOKEN
WORKFLOW_EXECUTION
CODE_EXECUTION
WEB_SEARCH
}
type Mutation {
@@ -676,7 +676,7 @@ export interface PageLayoutWidget {
__typename: 'PageLayoutWidget'
}
export type WidgetType = 'VIEW' | 'IFRAME' | 'FIELD' | 'FIELDS' | 'GRAPH' | 'STANDALONE_RICH_TEXT' | 'TIMELINE' | 'TASKS' | 'NOTES' | 'FILES' | 'EMAILS' | 'CALENDAR' | 'FIELD_RICH_TEXT' | 'WORKFLOW' | 'WORKFLOW_VERSION' | 'WORKFLOW_RUN' | 'FRONT_COMPONENT' | 'RECORD_TABLE'
export type WidgetType = 'VIEW' | 'IFRAME' | 'FIELD' | 'FIELDS' | 'GRAPH' | 'STANDALONE_RICH_TEXT' | 'TIMELINE' | 'TASKS' | 'NOTES' | 'FILES' | 'EMAILS' | 'CALENDAR' | 'FIELD_RICH_TEXT' | 'WORKFLOW' | 'WORKFLOW_VERSION' | 'WORKFLOW_RUN' | 'FRONT_COMPONENT' | 'RECORD_TABLE' | 'EMAIL_THREAD'
export type PageLayoutWidgetPosition = (PageLayoutWidgetGridPosition | PageLayoutWidgetVerticalListPosition | PageLayoutWidgetCanvasPosition) & { __isUnion?: true }
@@ -702,7 +702,7 @@ export interface PageLayoutWidgetCanvasPosition {
__typename: 'PageLayoutWidgetCanvasPosition'
}
export type WidgetConfiguration = (AggregateChartConfiguration | StandaloneRichTextConfiguration | PieChartConfiguration | LineChartConfiguration | IframeConfiguration | GaugeChartConfiguration | BarChartConfiguration | CalendarConfiguration | FrontComponentConfiguration | EmailsConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | NotesConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | RecordTableConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration) & { __isUnion?: true }
export type WidgetConfiguration = (AggregateChartConfiguration | StandaloneRichTextConfiguration | PieChartConfiguration | LineChartConfiguration | IframeConfiguration | GaugeChartConfiguration | BarChartConfiguration | CalendarConfiguration | FrontComponentConfiguration | EmailsConfiguration | EmailThreadConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | NotesConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | RecordTableConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration) & { __isUnion?: true }
export interface AggregateChartConfiguration {
configurationType: WidgetConfigurationType
@@ -721,7 +721,7 @@ export interface AggregateChartConfiguration {
__typename: 'AggregateChartConfiguration'
}
export type WidgetConfigurationType = 'AGGREGATE_CHART' | 'GAUGE_CHART' | 'PIE_CHART' | 'BAR_CHART' | 'LINE_CHART' | 'IFRAME' | 'STANDALONE_RICH_TEXT' | 'VIEW' | 'FIELD' | 'FIELDS' | 'TIMELINE' | 'TASKS' | 'NOTES' | 'FILES' | 'EMAILS' | 'CALENDAR' | 'FIELD_RICH_TEXT' | 'WORKFLOW' | 'WORKFLOW_VERSION' | 'WORKFLOW_RUN' | 'FRONT_COMPONENT' | 'RECORD_TABLE'
export type WidgetConfigurationType = 'AGGREGATE_CHART' | 'GAUGE_CHART' | 'PIE_CHART' | 'BAR_CHART' | 'LINE_CHART' | 'IFRAME' | 'STANDALONE_RICH_TEXT' | 'VIEW' | 'FIELD' | 'FIELDS' | 'TIMELINE' | 'TASKS' | 'NOTES' | 'FILES' | 'EMAILS' | 'CALENDAR' | 'FIELD_RICH_TEXT' | 'WORKFLOW' | 'WORKFLOW_VERSION' | 'WORKFLOW_RUN' | 'FRONT_COMPONENT' | 'RECORD_TABLE' | 'EMAIL_THREAD'
export interface StandaloneRichTextConfiguration {
configurationType: WidgetConfigurationType
@@ -869,6 +869,11 @@ export interface EmailsConfiguration {
__typename: 'EmailsConfiguration'
}
export interface EmailThreadConfiguration {
configurationType: WidgetConfigurationType
__typename: 'EmailThreadConfiguration'
}
export interface FieldConfiguration {
configurationType: WidgetConfigurationType
fieldMetadataId: Scalars['String']
@@ -1424,7 +1429,7 @@ export interface PublicFeatureFlag {
__typename: 'PublicFeatureFlag'
}
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED'
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED'
export interface ClientConfigMaintenanceMode {
startAt: Scalars['DateTime']
@@ -2250,7 +2255,7 @@ export interface ConnectedImapSmtpCaldavAccount {
id: Scalars['UUID']
handle: Scalars['String']
provider: Scalars['String']
accountOwnerId: Scalars['UUID']
userWorkspaceId: Scalars['UUID']
connectionParameters?: ImapSmtpCaldavConnectionParameters
__typename: 'ConnectedImapSmtpCaldavAccount'
}
@@ -2290,7 +2295,7 @@ export interface CommandMenuItem {
__typename: 'CommandMenuItem'
}
export type EngineComponentKey = 'NAVIGATE_TO_NEXT_RECORD' | 'NAVIGATE_TO_PREVIOUS_RECORD' | 'CREATE_NEW_RECORD' | 'DELETE_RECORDS' | 'RESTORE_RECORDS' | 'DESTROY_RECORDS' | 'ADD_TO_FAVORITES' | 'REMOVE_FROM_FAVORITES' | 'EXPORT_NOTE_TO_PDF' | 'EXPORT_RECORDS' | 'UPDATE_MULTIPLE_RECORDS' | 'MERGE_MULTIPLE_RECORDS' | 'IMPORT_RECORDS' | 'EXPORT_VIEW' | 'SEE_DELETED_RECORDS' | 'CREATE_NEW_VIEW' | 'HIDE_DELETED_RECORDS' | 'GO_TO_PEOPLE' | 'GO_TO_COMPANIES' | 'GO_TO_DASHBOARDS' | 'GO_TO_OPPORTUNITIES' | 'GO_TO_SETTINGS' | 'GO_TO_TASKS' | 'GO_TO_NOTES' | 'EDIT_RECORD_PAGE_LAYOUT' | 'EDIT_DASHBOARD_LAYOUT' | 'SAVE_DASHBOARD_LAYOUT' | 'CANCEL_DASHBOARD_LAYOUT' | 'DUPLICATE_DASHBOARD' | 'GO_TO_WORKFLOWS' | 'ACTIVATE_WORKFLOW' | 'DEACTIVATE_WORKFLOW' | 'DISCARD_DRAFT_WORKFLOW' | 'TEST_WORKFLOW' | 'SEE_ACTIVE_VERSION_WORKFLOW' | 'SEE_RUNS_WORKFLOW' | 'SEE_VERSIONS_WORKFLOW' | 'ADD_NODE_WORKFLOW' | 'TIDY_UP_WORKFLOW' | 'DUPLICATE_WORKFLOW' | 'GO_TO_RUNS' | 'SEE_VERSION_WORKFLOW_RUN' | 'SEE_WORKFLOW_WORKFLOW_RUN' | 'STOP_WORKFLOW_RUN' | 'SEE_RUNS_WORKFLOW_VERSION' | 'SEE_WORKFLOW_WORKFLOW_VERSION' | 'USE_AS_DRAFT_WORKFLOW_VERSION' | 'SEE_VERSIONS_WORKFLOW_VERSION' | 'SEARCH_RECORDS' | 'SEARCH_RECORDS_FALLBACK' | 'ASK_AI' | 'VIEW_PREVIOUS_AI_CHATS' | 'TRIGGER_WORKFLOW_VERSION' | 'FRONT_COMPONENT_RENDERER' | 'DELETE_SINGLE_RECORD' | 'DELETE_MULTIPLE_RECORDS' | 'RESTORE_SINGLE_RECORD' | 'RESTORE_MULTIPLE_RECORDS' | 'DESTROY_SINGLE_RECORD' | 'DESTROY_MULTIPLE_RECORDS' | 'EXPORT_FROM_RECORD_INDEX' | 'EXPORT_FROM_RECORD_SHOW' | 'EXPORT_MULTIPLE_RECORDS'
export type EngineComponentKey = 'NAVIGATE_TO_NEXT_RECORD' | 'NAVIGATE_TO_PREVIOUS_RECORD' | 'CREATE_NEW_RECORD' | 'DELETE_RECORDS' | 'RESTORE_RECORDS' | 'DESTROY_RECORDS' | 'ADD_TO_FAVORITES' | 'REMOVE_FROM_FAVORITES' | 'EXPORT_NOTE_TO_PDF' | 'EXPORT_RECORDS' | 'UPDATE_MULTIPLE_RECORDS' | 'MERGE_MULTIPLE_RECORDS' | 'IMPORT_RECORDS' | 'EXPORT_VIEW' | 'SEE_DELETED_RECORDS' | 'CREATE_NEW_VIEW' | 'HIDE_DELETED_RECORDS' | 'GO_TO_PEOPLE' | 'GO_TO_COMPANIES' | 'GO_TO_DASHBOARDS' | 'GO_TO_OPPORTUNITIES' | 'GO_TO_SETTINGS' | 'GO_TO_TASKS' | 'GO_TO_NOTES' | 'EDIT_RECORD_PAGE_LAYOUT' | 'EDIT_DASHBOARD_LAYOUT' | 'SAVE_DASHBOARD_LAYOUT' | 'CANCEL_DASHBOARD_LAYOUT' | 'DUPLICATE_DASHBOARD' | 'GO_TO_WORKFLOWS' | 'ACTIVATE_WORKFLOW' | 'DEACTIVATE_WORKFLOW' | 'DISCARD_DRAFT_WORKFLOW' | 'TEST_WORKFLOW' | 'SEE_ACTIVE_VERSION_WORKFLOW' | 'SEE_RUNS_WORKFLOW' | 'SEE_VERSIONS_WORKFLOW' | 'ADD_NODE_WORKFLOW' | 'TIDY_UP_WORKFLOW' | 'DUPLICATE_WORKFLOW' | 'GO_TO_RUNS' | 'SEE_VERSION_WORKFLOW_RUN' | 'SEE_WORKFLOW_WORKFLOW_RUN' | 'STOP_WORKFLOW_RUN' | 'SEE_RUNS_WORKFLOW_VERSION' | 'SEE_WORKFLOW_WORKFLOW_VERSION' | 'USE_AS_DRAFT_WORKFLOW_VERSION' | 'SEE_VERSIONS_WORKFLOW_VERSION' | 'SEARCH_RECORDS' | 'SEARCH_RECORDS_FALLBACK' | 'ASK_AI' | 'VIEW_PREVIOUS_AI_CHATS' | 'TRIGGER_WORKFLOW_VERSION' | 'FRONT_COMPONENT_RENDERER' | 'REPLY_TO_EMAIL_THREAD' | 'DELETE_SINGLE_RECORD' | 'DELETE_MULTIPLE_RECORDS' | 'RESTORE_SINGLE_RECORD' | 'RESTORE_MULTIPLE_RECORDS' | 'DESTROY_SINGLE_RECORD' | 'DESTROY_MULTIPLE_RECORDS' | 'EXPORT_FROM_RECORD_INDEX' | 'EXPORT_FROM_RECORD_SHOW' | 'EXPORT_MULTIPLE_RECORDS'
export type CommandMenuItemAvailabilityType = 'GLOBAL' | 'RECORD_SELECTION' | 'FALLBACK'
@@ -2628,7 +2633,7 @@ export interface MessageFolder {
name?: Scalars['String']
isSentFolder: Scalars['Boolean']
isSynced: Scalars['Boolean']
parentFolderId?: Scalars['UUID']
parentFolderId?: Scalars['String']
externalId?: Scalars['String']
pendingSyncAction: MessageFolderPendingSyncAction
messageChannelId: Scalars['UUID']
@@ -2819,7 +2824,7 @@ export type SortNulls = 'NULLS_FIRST' | 'NULLS_LAST'
export type EventLogTable = 'WORKSPACE_EVENT' | 'PAGEVIEW' | 'OBJECT_EVENT' | 'USAGE_EVENT'
export type UsageOperationType = 'AI_CHAT_TOKEN' | 'AI_WORKFLOW_TOKEN' | 'WORKFLOW_EXECUTION' | 'CODE_EXECUTION'
export type UsageOperationType = 'AI_CHAT_TOKEN' | 'AI_WORKFLOW_TOKEN' | 'WORKFLOW_EXECUTION' | 'CODE_EXECUTION' | 'WEB_SEARCH'
export interface Mutation {
addQueryToEventStream: Scalars['Boolean']
@@ -3790,6 +3795,7 @@ export interface WidgetConfigurationGenqlSelection{
on_CalendarConfiguration?:CalendarConfigurationGenqlSelection,
on_FrontComponentConfiguration?:FrontComponentConfigurationGenqlSelection,
on_EmailsConfiguration?:EmailsConfigurationGenqlSelection,
on_EmailThreadConfiguration?:EmailThreadConfigurationGenqlSelection,
on_FieldConfiguration?:FieldConfigurationGenqlSelection,
on_FieldRichTextConfiguration?:FieldRichTextConfigurationGenqlSelection,
on_FieldsConfiguration?:FieldsConfigurationGenqlSelection,
@@ -3958,6 +3964,12 @@ export interface EmailsConfigurationGenqlSelection{
__scalar?: boolean | number
}
export interface EmailThreadConfigurationGenqlSelection{
configurationType?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface FieldConfigurationGenqlSelection{
configurationType?: boolean | number
fieldMetadataId?: boolean | number
@@ -5431,7 +5443,7 @@ export interface ConnectedImapSmtpCaldavAccountGenqlSelection{
id?: boolean | number
handle?: boolean | number
provider?: boolean | number
accountOwnerId?: boolean | number
userWorkspaceId?: boolean | number
connectionParameters?: ImapSmtpCaldavConnectionParametersGenqlSelection
__typename?: boolean | number
__scalar?: boolean | number
@@ -6956,7 +6968,7 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
const WidgetConfiguration_possibleTypes: string[] = ['AggregateChartConfiguration','StandaloneRichTextConfiguration','PieChartConfiguration','LineChartConfiguration','IframeConfiguration','GaugeChartConfiguration','BarChartConfiguration','CalendarConfiguration','FrontComponentConfiguration','EmailsConfiguration','FieldConfiguration','FieldRichTextConfiguration','FieldsConfiguration','FilesConfiguration','NotesConfiguration','TasksConfiguration','TimelineConfiguration','ViewConfiguration','RecordTableConfiguration','WorkflowConfiguration','WorkflowRunConfiguration','WorkflowVersionConfiguration']
const WidgetConfiguration_possibleTypes: string[] = ['AggregateChartConfiguration','StandaloneRichTextConfiguration','PieChartConfiguration','LineChartConfiguration','IframeConfiguration','GaugeChartConfiguration','BarChartConfiguration','CalendarConfiguration','FrontComponentConfiguration','EmailsConfiguration','EmailThreadConfiguration','FieldConfiguration','FieldRichTextConfiguration','FieldsConfiguration','FilesConfiguration','NotesConfiguration','TasksConfiguration','TimelineConfiguration','ViewConfiguration','RecordTableConfiguration','WorkflowConfiguration','WorkflowRunConfiguration','WorkflowVersionConfiguration']
export const isWidgetConfiguration = (obj?: { __typename?: any } | null): obj is WidgetConfiguration => {
if (!obj?.__typename) throw new Error('__typename is missing in "isWidgetConfiguration"')
return WidgetConfiguration_possibleTypes.includes(obj.__typename)
@@ -7044,6 +7056,14 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
const EmailThreadConfiguration_possibleTypes: string[] = ['EmailThreadConfiguration']
export const isEmailThreadConfiguration = (obj?: { __typename?: any } | null): obj is EmailThreadConfiguration => {
if (!obj?.__typename) throw new Error('__typename is missing in "isEmailThreadConfiguration"')
return EmailThreadConfiguration_possibleTypes.includes(obj.__typename)
}
const FieldConfiguration_possibleTypes: string[] = ['FieldConfiguration']
export const isFieldConfiguration = (obj?: { __typename?: any } | null): obj is FieldConfiguration => {
if (!obj?.__typename) throw new Error('__typename is missing in "isFieldConfiguration"')
@@ -8912,7 +8932,8 @@ export const enumWidgetType = {
WORKFLOW_VERSION: 'WORKFLOW_VERSION' as const,
WORKFLOW_RUN: 'WORKFLOW_RUN' as const,
FRONT_COMPONENT: 'FRONT_COMPONENT' as const,
RECORD_TABLE: 'RECORD_TABLE' as const
RECORD_TABLE: 'RECORD_TABLE' as const,
EMAIL_THREAD: 'EMAIL_THREAD' as const
}
export const enumPageLayoutTabLayoutMode = {
@@ -8943,7 +8964,8 @@ export const enumWidgetConfigurationType = {
WORKFLOW_VERSION: 'WORKFLOW_VERSION' as const,
WORKFLOW_RUN: 'WORKFLOW_RUN' as const,
FRONT_COMPONENT: 'FRONT_COMPONENT' as const,
RECORD_TABLE: 'RECORD_TABLE' as const
RECORD_TABLE: 'RECORD_TABLE' as const,
EMAIL_THREAD: 'EMAIL_THREAD' as const
}
export const enumObjectRecordGroupByDateGranularity = {
@@ -9101,7 +9123,6 @@ export const enumFeatureFlagKey = {
IS_USAGE_ANALYTICS_ENABLED: 'IS_USAGE_ANALYTICS_ENABLED' as const,
IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const,
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const,
IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const,
IS_RECORD_TABLE_WIDGET_ENABLED: 'IS_RECORD_TABLE_WIDGET_ENABLED' as const,
IS_DATASOURCE_MIGRATED: 'IS_DATASOURCE_MIGRATED' as const
}
@@ -9252,6 +9273,7 @@ export const enumEngineComponentKey = {
VIEW_PREVIOUS_AI_CHATS: 'VIEW_PREVIOUS_AI_CHATS' as const,
TRIGGER_WORKFLOW_VERSION: 'TRIGGER_WORKFLOW_VERSION' as const,
FRONT_COMPONENT_RENDERER: 'FRONT_COMPONENT_RENDERER' as const,
REPLY_TO_EMAIL_THREAD: 'REPLY_TO_EMAIL_THREAD' as const,
DELETE_SINGLE_RECORD: 'DELETE_SINGLE_RECORD' as const,
DELETE_MULTIPLE_RECORDS: 'DELETE_MULTIPLE_RECORDS' as const,
RESTORE_SINGLE_RECORD: 'RESTORE_SINGLE_RECORD' as const,
@@ -9408,7 +9430,8 @@ export const enumUsageOperationType = {
AI_CHAT_TOKEN: 'AI_CHAT_TOKEN' as const,
AI_WORKFLOW_TOKEN: 'AI_WORKFLOW_TOKEN' as const,
WORKFLOW_EXECUTION: 'WORKFLOW_EXECUTION' as const,
CODE_EXECUTION: 'CODE_EXECUTION' as const
CODE_EXECUTION: 'CODE_EXECUTION' as const,
WEB_SEARCH: 'WEB_SEARCH' as const
}
export const enumAnalyticsType = {
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Dit sal dit permanent uit die waglyn verwyder. H
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Dit sal die geselekteerde werk herprobeer. Dit sal van vooraf weer uitgevoer word.} other {Dit sal die geselekteerde werke herprobeer. Hulle sal van vooraf weer uitgevoer word.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "E-pos of domein is reeds in bloklys"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-posdraad"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Laai vaardighede..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Laai draad"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Herskik opsies"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Reageer"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, zero {سيتم إزالة {jobCount} نهائيًا
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, zero {سيتم إعادة محاولة {jobCount} وظائف. سيتم تنفيذهم مجددًا من البداية.} one {سيتم إعادة محاولة الوظيفة المحددة. سيتم تنفيذها من البداية.} two {سيتم إعادة المحاولة للوظائف المحددة. سيتم تنفيذهم من البداية.} few {سيتم إعادة المحاولة للوظائف المحددة. سيتم تنفيذهم من البداية.} many {سيتم إعادة المحاولة للوظائف المحددة. سيتم تنفيذهم من البداية.} other {سيتم إعادة المحاولة للوظائف المحددة. سيتم تنفيذهم من البداية.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "البريد الإلكتروني أو النطاق مدرج بالفع
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "سلسلة البريد الإلكتروني"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "جارٍ تحميل المهارات..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "جارٍ تحميل السلسلة"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "إعادة ترتيب الخيارات"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "الرد"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Això eliminarà permanentment la cua. Aquesta a
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Això tornarà a intentar la feina seleccionada. Es tornarà a executar des del principi.} other {Això tornarà a intentar les feines seleccionades. Es tornaran a executar des del principi.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "El correu electrònic o domini ja està en la llista de bloqueig"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Fil de correu electrònic"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Carregant habilitats..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Carregant el fil"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr ""
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Respon"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Tato akce ji trvale odstraní z fronty. Tuto akc
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Tato akce znovu spustí vybranou úlohu. Bude spuštěna znovu od začátku.} few {Tato akce znovu spustí vybrané úlohy. Budou spuštěny znovu od začátku.} many {Tato akce znovu spustí vybrané úlohy. Budou spuštěny znovu od začátku.} other {Tato akce znovu spustí vybrané úlohy. Budou spuštěny znovu od začátku.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "E-mail nebo doména již je v seznamu blokovaných"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-mailové vlákno"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Načítání dovedností..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Načítání vlákna"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Změnit pořadí možností"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Odpovědět"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Dette vil permanent fjerne det fra køen. Denne
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Dette vil forsøge det valgte job igen. Det vil blive udført fra begyndelsen.} other {Dette vil forsøge de valgte jobs igen. De vil blive udført fra begyndelsen.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "E-mail eller domæne er allerede på blokeringslisten"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-mail-tråd"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Indlæser færdigheder..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Indlæser tråd"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Omarranger valgmuligheder"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Svar"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Dies wird es dauerhaft von der Warteschlange ent
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Dies wird den ausgewählten Auftrag neu ausführen. Er wird von Anfang an neu ausgeführt.} other {Dies wird die ausgewählten Aufträge neu ausführen. Sie werden von Anfang an neu ausgeführt.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "E-Mail oder Domain ist bereits in der Blockliste"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-Mail-Thread"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Skills werden geladen..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Thread wird geladen"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Optionen neu anordnen"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Antworten"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Αυτό θα την αφαιρέσει ορισ
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Αυτό θα επαναλάβει την επιλεγμένη εργασία. Θα εκτελεστεί από την αρχή.} other {Αυτό θα επαναλάβει τις επιλεγμένες εργασίες. Θα εκτελεστούν από την αρχή.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Το email ή ο τομέας βρίσκεται ήδη στη λίστ
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Νήμα email"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Φόρτωση δεξιοτήτων..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Φόρτωση νήματος"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Αναδιάταξη επιλογών"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Απάντηση"
+6 -7
View File
@@ -311,6 +311,11 @@ msgstr "{jobCount, plural, one {This will permanently remove it from the queue.
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr "{messagesLength} emails"
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5345,11 +5350,6 @@ msgstr "Email or domain is already in blocklist"
msgid "Email support"
msgstr "Email support"
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Email Thread"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8572,7 +8572,7 @@ msgid "Loading skills..."
msgstr "Loading skills..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Loading thread"
@@ -11745,7 +11745,6 @@ msgid "Reorder options"
msgstr "Reorder options"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Reply"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Esto lo eliminará permanentemente de la cola. E
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Esto reintentará el trabajo seleccionado. Será reejecutado desde el principio.} other {Esto reintentará los trabajos seleccionados. Serán reejecutados desde el principio.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "El correo electrónico o el dominio ya están en la lista de bloqueo"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Hilo de correo electrónico"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Cargando habilidades..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Cargando hilo"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Reordenar opciones"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Responder"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Tämä poistaa sen pysyvästi jonosta. Tämä to
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Tämä yrittää valittua työtä uudelleen. Se suoritetaan alusta alkaen uudelleen.} other {Tämä yrittää valittuja töitä uudelleen. Ne suoritetaan alusta alkaen uudelleen.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Sähköposti tai verkkotunnus on jo estolistalla"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Sähköpostiketju"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Ladataan taitoja..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Ladataan ketjua"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Järjestä vaihtoehdot uudelleen"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Vastaa"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Cela le retirera définitivement de la file d'at
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Ceci va réessayer la tâche sélectionnée. Elle sera ré-exécutée depuis le début.} other {Ceci va réessayer les tâches sélectionnées. Elles seront ré-exécutées depuis le début.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Le courriel ou le domaine est déjà dans la liste de blocage"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Fil de discussion e-mail"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Chargement des compétences..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Chargement du fil de discussion"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Réordonner les options"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Répondre"
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {זה יסיר אותה מהתור לצמיתות
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {זה ינסה להפעיל מחדש את העבודה הנבחרת. היא תבוצע שוב מההתחלה.} two {זה ינסה להפעיל מחדש את העבודות הנבחרות. הן תבוצענה שוב מההתחלה.} many {זה ינסה להפעיל מחדש את העבודות הנבחרות. הן תבוצענה שוב מההתחלה.} other {זה ינסה להפעיל מחדש את העבודות הנבחרות. הן תבוצענה שוב מההתחלה.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "דוא\"ל או תחום כבר נמצאים ברשימת החסימה"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "שרשור דוא\"ל"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "טוען מיומנויות..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "טוען שרשור"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "סדר אופציות מחדש"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "תגובה"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Ez végleg törölni fogja a sorból. Ez a műve
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Ez újraindítja a kijelölt állást. Újra végrehajtásra kerül az elejétől.} other {Ez újraindítja a kijelölt állásokat. Újra végrehajtásra kerülnek az elejétől.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Az email vagy domain már szerepel a tiltólistában"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-mail szál"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Készségek betöltése..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Szál betöltése"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Opciók átrendezése"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Válasz"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Questo lo rimuoverà definitivamente dalla coda.
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Questo riproverà il lavoro selezionato. Verrà rieseguito dall'inizio.} other {Questo riproverà i lavori selezionati. Verranno rieseguiti dall'inizio.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "L'e-mail o il dominio è già presente nella lista di blocco"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Thread email"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Caricamento abilità..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Caricamento del thread"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Riordina opzioni"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Rispondi"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, other {これによりキューから永久に削除
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, other {選択されたジョブを再試行します。最初から再実行されます。}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "メールまたはドメインはすでにブロックリストに登録
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "メールスレッド"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "スキルを読み込み中..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "スレッドを読み込み中"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "オプションを並べ替え"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "返信"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, other {이 작업들은 대기열에서 영구적으
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, other {선택된 작업들을 재시도합니다. 처음부터 다시 실행됩니다.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "이메일 또는 도메인이 이미 차단 목록에 있습니다"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "이메일 스레드"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "스킬 로드 중..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "스레드 로드 중"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "옵션 재정렬"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "답장"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Dit zal het permanent uit de wachtrij verwijdere
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Dit zal de geselecteerde taak opnieuw proberen. Het wordt opnieuw uitgevoerd vanaf het begin.} other {Dit zal de geselecteerde taken opnieuw proberen. Ze worden opnieuw uitgevoerd vanaf het begin.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "E-mail of domein staat al in de blokkeerlijst"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-mailthread"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Vaardigheden laden..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Conversatie laden"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Opties opnieuw ordenen"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Antwoord"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Dette vil permanent fjerne det fra køen. Denne
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Dette vil prøve den valgte jobben på nytt. Den vil bli kjør fra begynnelsen.} other {Dette vil prøve de valgte jobbene på nytt. De vil bli kjørt fra begynnelsen.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "E-post eller domene er allerede i svartelisten"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-posttråd"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Laster ferdigheter..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Laster tråd"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Endre rekkefølgen på alternativer"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Svar"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {To trwale usunie go z kolejki. Tej akcji nie mo
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {To ponownie uruchomi wybrane zadanie. Zostanie ono wykonane od początku.} few {To ponownie uruchomi wybrane zadania. Zostaną one wykonane od początku.} many {To ponownie uruchomi wybrane zadania. Zostaną one wykonane od początku.} other {To ponownie uruchomi wybrane zadania. Zostaną one wykonane od początku.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Email lub domena jest już na liście blokowanych"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Wątek e-maila"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Ładowanie umiejętności..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Ładowanie wątku"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Zmień kolejność opcji"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Odpowiedz"
@@ -311,6 +311,11 @@ msgstr ""
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr ""
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5345,11 +5350,6 @@ msgstr ""
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr ""
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8572,7 +8572,7 @@ msgid "Loading skills..."
msgstr ""
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr ""
@@ -11745,7 +11745,6 @@ msgid "Reorder options"
msgstr ""
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr ""
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Isso irá removê-lo permanentemente da fila. Es
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Isso irá repetir o trabalho selecionado. Ele será reexecutado do início.} other {Isso irá repetir os trabalhos selecionados. Eles serão reexecutados do início.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "O e-mail ou domínio já está na lista de bloqueio"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Tópico de e-mail"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr ""
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Carregando tópico"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Reordenar opções"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Responder"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Isso irá removê-lo permanentemente da fila. Es
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Isso irá reiniciar o trabalho selecionado. Ele será re-executado desde o início.} other {Isso irá reiniciar os trabalhos selecionados. Eles serão re-executados desde o início.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "O e-mail ou domínio já está na lista de bloqueio"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Fio de E-mail"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Carregando habilidades..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "A carregar a conversa"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Reordenar opções"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Responder"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Acest lucru îl va elimina permanent din coadă.
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Aceasta va reîncerca locul de muncă selectat. Va fi re-executat de la început.} few {Aceasta va reîncerca locurile de muncă selectate. Vor fi re-executate de la început.} other {Aceasta va reîncerca locurile de muncă selectate. Vor fi re-executate de la început.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Emailul sau domeniul este deja în lista de blocare"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Fir de e-mail"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Se încarcă abilitățile..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Se încarcă firul"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Reordonează opțiunile"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Răspunde"
Binary file not shown.
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Ово ће трајно уклонити из
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Ово ће поновити изабрани посао. Поново ће се извршити од почетка.} few {Ово ће поновити изабране послове. Поново ће се извршити од почетка.} other {Ово ће поновити изабране послове. Поново ће се извршити од почетка.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Имејл или домен су већ на листи блокира
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Нит имејла"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Учитавање вештина..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Учитавање нити"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Промени редослед опција"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Одговори"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Detta kommer permanent ta bort det från kön. D
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Detta kommer att försöka igen det valda arbetet. Det kommer att köras om från början.} other {Detta kommer att försöka igen de valda arbetena. De kommer att köras om från början.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "E-post eller domän finns redan i blocklistan"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-posttråd"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Laddar färdigheter..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Laddar tråd"
@@ -11752,7 +11752,6 @@ msgid "Reorder options"
msgstr "Ändra ordning på alternativen"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Svara"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Bunu sıradan kalıcı olarak kaldıracak. Bu i
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Seçilen iş yeniden denenecek. Başından başlayarak yeniden yürütülecek.} other {Seçilen işler yeniden denenecek. Başından başlayarak yeniden yürütülecek.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "E-posta veya alan adı zaten engellenmişler listesinde"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "E-posta Dizisi"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Beceriler yükleniyor..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Dizi yükleniyor"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Seçenekleri yeniden sırala"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Cevapla"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, one {Це видалить його з черги н
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, one {Це повторить обране завдання. Воно буде виконане з самого початку.} few {Це повторить обрані завдання. Вони будуть виконані з самого початку.} many {Це повторить обрані завдання. Вони будуть виконані з самого початку.} other {Це повторить обрані завдання. Вони будуть виконані з самого початку.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Електронна пошта або домен вже знаходя
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Ланцюжок електронних листів"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Завантаження навичок..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Завантаження ланцюжка"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Змінити порядок опцій"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Відповісти"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, other {Điều này sẽ xóa chúng khỏi hàng đ
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, other {Điều này sẽ thử lại các công việc đã chọn. Chúng sẽ được thực hiện lại từ đầu.}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "Email hoặc tên miền đã nằm trong danh sách chặn"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "Chuỗi email"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "Đang tải kỹ năng..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "Đang tải chuỗi"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "Sắp xếp lại các tùy chọn"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "Trả lời"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr ""
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr ""
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "电子邮件或域已在拦截列表中"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "电子邮件线程"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "正在加载技能..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "正在加载会话"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "调整选项顺序"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "回复"
+6 -7
View File
@@ -316,6 +316,11 @@ msgstr "{jobCount, plural, other {這將從隊列中永久移除它們。此操
msgid "{jobCount, plural, one {This will retry the selected job. It will be re-executed from the beginning.} other {This will retry the selected jobs. They will be re-executed from the beginning.}}"
msgstr "{jobCount, plural, other {這將重試選定的工作。它們將從頭開始重新執行。}}"
#. js-lingui-id: Y32cMj
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages.tsx
msgid "{messagesLength} emails"
msgstr ""
#. js-lingui-id: Koe99p
#: src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx
#: src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx
@@ -5350,11 +5355,6 @@ msgstr "電子郵件或域名已在阻止列表中"
msgid "Email support"
msgstr ""
#. js-lingui-id: +VjrH/
#: src/modules/side-panel/hooks/useOpenEmailThreadInSidePanel.ts
msgid "Email Thread"
msgstr "電子郵件串"
#. js-lingui-id: LimKOG
#: src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
msgid "Email verification"
@@ -8577,7 +8577,7 @@ msgid "Loading skills..."
msgstr "正在載入技能..."
#. js-lingui-id: 7YK6ap
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/page-layout/widgets/email-thread/components/EmailThreadWidget.tsx
msgid "Loading thread"
msgstr "正在載入郵件串"
@@ -11750,7 +11750,6 @@ msgid "Reorder options"
msgstr "重新排序選項"
#. js-lingui-id: ImOQa9
#: src/modules/side-panel/pages/message-thread/components/SidePanelMessageThreadPage.tsx
#: src/modules/activities/emails/components/EmailThreadBottomBar.tsx
msgid "Reply"
msgstr "回覆"
@@ -2,9 +2,10 @@ import { styled } from '@linaria/react';
import { ActivityRow } from '@/activities/components/ActivityRow';
import { EmailThreadNotShared } from '@/activities/emails/components/EmailThreadNotShared';
import { useOpenEmailThreadInSidePanel } from '@/side-panel/hooks/useOpenEmailThreadInSidePanel';
import { useOpenRecordInSidePanel } from '@/side-panel/hooks/useOpenRecordInSidePanel';
import { useContext } from 'react';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { Avatar } from 'twenty-ui/display';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
@@ -77,7 +78,7 @@ type EmailThreadPreviewProps = {
export const EmailThreadPreview = ({ thread }: EmailThreadPreviewProps) => {
const { theme } = useContext(ThemeContext);
const { openEmailThreadInSidePanel } = useOpenEmailThreadInSidePanel();
const { openRecordInSidePanel } = useOpenRecordInSidePanel();
const visibility = thread.visibility;
@@ -104,7 +105,10 @@ export const EmailThreadPreview = ({ thread }: EmailThreadPreviewProps) => {
thread.visibility === MessageChannelVisibility.SHARE_EVERYTHING;
if (canOpen) {
openEmailThreadInSidePanel(thread.id);
openRecordInSidePanel({
recordId: thread.id,
objectNameSingular: CoreObjectNameSingular.MessageThread,
});
}
};
@@ -1,29 +1,22 @@
import { useCallback, useEffect, useState } from 'react';
import { type MessageChannel } from '@/accounts/types/MessageChannel';
import { fetchAllThreadMessagesOperationSignatureFactory } from '@/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory';
import { type EmailThread } from '@/activities/emails/types/EmailThread';
import { type EmailThreadMessage } from '@/activities/emails/types/EmailThreadMessage';
import { type MessageChannel } from '@/accounts/types/MessageChannel';
import { type EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
import { type EmailThreadMessageWithSender } from '@/activities/emails/types/EmailThreadMessageWithSender';
import { type MessageChannelMessageAssociation } from '@/activities/emails/types/MessageChannelMessageAssociation';
import { viewableRecordIdComponentState } from '@/side-panel/pages/record-page/states/viewableRecordIdComponentState';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import {
CoreObjectNameSingular,
MessageParticipantRole,
} from 'twenty-shared/types';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { isDefined } from 'twenty-shared/utils';
// to improve - https://github.com/twentyhq/twenty/issues/12190
export const useEmailThreadInSidePanel = () => {
const viewableRecordId = useAtomComponentStateValue(
viewableRecordIdComponentState,
);
export const useEmailThread = (threadId: string | null) => {
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const [lastMessageId, setLastMessageId] = useState<string | null>(null);
const [lastMessageChannelId, setLastMessageChannelId] = useState<
@@ -33,7 +26,7 @@ export const useEmailThreadInSidePanel = () => {
const { record: thread } = useFindOneRecord<EmailThread>({
objectNameSingular: CoreObjectNameSingular.MessageThread,
objectRecordId: viewableRecordId ?? '',
objectRecordId: threadId ?? '',
recordGqlFields: {
id: true,
},
@@ -47,7 +40,7 @@ export const useEmailThreadInSidePanel = () => {
const FETCH_ALL_MESSAGES_OPERATION_SIGNATURE =
fetchAllThreadMessagesOperationSignatureFactory({
messageThreadId: viewableRecordId,
messageThreadId: threadId,
});
const {
@@ -62,7 +55,7 @@ export const useEmailThreadInSidePanel = () => {
FETCH_ALL_MESSAGES_OPERATION_SIGNATURE.objectNameSingular,
orderBy: FETCH_ALL_MESSAGES_OPERATION_SIGNATURE.variables.orderBy,
recordGqlFields: FETCH_ALL_MESSAGES_OPERATION_SIGNATURE.fields,
skip: !viewableRecordId,
skip: !threadId,
});
const fetchMoreMessages = useCallback(() => {
@@ -76,11 +69,11 @@ export const useEmailThreadInSidePanel = () => {
useEffect(() => {
if (messages.length > 0 && isMessagesFetchComplete) {
const lastMessage = messages[messages.length - 1];
setLastMessageId(lastMessage.id);
}
}, [messages, isMessagesFetchComplete]);
// TODO: introduce nested filters so we can retrieve the message sender directly from the message query
const { records: messageSenders } =
useFindManyRecords<EmailThreadMessageParticipant>({
filter: {
@@ -167,9 +160,11 @@ export const useEmailThreadInSidePanel = () => {
const sender = messageSenders.find(
(messageSender) => messageSender.messageId === message.id,
);
if (!sender) {
return null;
}
return {
...message,
sender,
@@ -3,7 +3,7 @@ import { styled } from '@linaria/react';
import { type EmailThreadMessage } from '@/activities/emails/types/EmailThreadMessage';
import { EventCardMessageBodyNotShared } from '@/activities/timeline-activities/rows/message/components/EventCardMessageBodyNotShared';
import { EventCardMessageForbidden } from '@/activities/timeline-activities/rows/message/components/EventCardMessageForbidden';
import { useOpenEmailThreadInSidePanel } from '@/side-panel/hooks/useOpenEmailThreadInSidePanel';
import { useOpenRecordInSidePanel } from '@/side-panel/hooks/useOpenRecordInSidePanel';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { Trans, useLingui } from '@lingui/react/macro';
@@ -62,7 +62,7 @@ export const EventCardMessage = ({
authorFullName: string;
}) => {
const { t } = useLingui();
const { openEmailThreadInSidePanel } = useOpenEmailThreadInSidePanel();
const { openRecordInSidePanel } = useOpenRecordInSidePanel();
const {
record: message,
@@ -133,7 +133,10 @@ export const EventCardMessage = ({
const handleClick = () => {
if (canOpen && isDefined(message.messageThreadId)) {
openEmailThreadInSidePanel(message.messageThreadId);
openRecordInSidePanel({
recordId: message.messageThreadId,
objectNameSingular: CoreObjectNameSingular.MessageThread,
});
}
};
@@ -40,6 +40,7 @@ import { TestWorkflowSingleRecordCommand } from '@/command-menu-item/engine-comm
import { TidyUpWorkflowSingleRecordCommand } from '@/command-menu-item/engine-command/record/single-record/workflow/components/TidyUpWorkflowSingleRecordCommand';
import { HeadlessFrontComponentRendererEngineCommand } from '@/command-menu-item/engine-command/components/HeadlessFrontComponentRendererEngineCommand';
import { TriggerWorkflowVersionEngineCommand } from '@/command-menu-item/engine-command/record/components/TriggerWorkflowVersionEngineCommand';
import { ReplyToEmailThreadCommand } from '@/command-menu-item/engine-command/record/single-record/message-thread/components/ReplyToEmailThreadCommand';
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
import { msg } from '@lingui/core/macro';
import { AppPath, SettingsPath, SidePanelPages } from 'twenty-shared/types';
@@ -240,6 +241,7 @@ export const ENGINE_COMPONENT_KEY_COMPONENT_MAP: Record<
[EngineComponentKey.FRONT_COMPONENT_RENDERER]: (
<HeadlessFrontComponentRendererEngineCommand />
),
[EngineComponentKey.REPLY_TO_EMAIL_THREAD]: <ReplyToEmailThreadCommand />,
// Deprecated keys kept for backward compatibility until migration runs
[EngineComponentKey.DELETE_SINGLE_RECORD]: <DeleteRecordsCommand />,
@@ -0,0 +1,78 @@
import { useMemo } from 'react';
import { useEmailThread } from '@/activities/emails/hooks/useEmailThread';
import { HeadlessEngineCommandWrapperEffect } from '@/command-menu-item/engine-command/components/HeadlessEngineCommandWrapperEffect';
import { useHeadlessCommandContextApi } from '@/command-menu-item/engine-command/hooks/useHeadlessCommandContextApi';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
const ALLOWED_REPLY_PROVIDERS = [
ConnectedAccountProvider.GOOGLE,
ConnectedAccountProvider.MICROSOFT,
ConnectedAccountProvider.IMAP_SMTP_CALDAV,
];
export const ReplyToEmailThreadCommand = () => {
const { selectedRecords } = useHeadlessCommandContextApi();
const threadId = selectedRecords[0]?.id ?? null;
const {
messageThreadExternalId,
connectedAccountHandle,
connectedAccountProvider,
lastMessageExternalId,
connectedAccountConnectionParameters,
messageChannelLoading,
} = useEmailThread(threadId);
const canReply = useMemo(() => {
return (
isDefined(connectedAccountHandle) &&
isDefined(connectedAccountProvider) &&
ALLOWED_REPLY_PROVIDERS.includes(connectedAccountProvider) &&
(connectedAccountProvider !== ConnectedAccountProvider.IMAP_SMTP_CALDAV ||
isDefined(connectedAccountConnectionParameters?.SMTP)) &&
isDefined(messageThreadExternalId)
);
}, [
connectedAccountConnectionParameters,
connectedAccountHandle,
connectedAccountProvider,
messageThreadExternalId,
]);
const handleExecute = () => {
if (!canReply) {
return;
}
switch (connectedAccountProvider) {
case ConnectedAccountProvider.MICROSOFT: {
const url = `https://outlook.office.com/mail/deeplink?ItemID=${lastMessageExternalId}`;
window.open(url, '_blank');
break;
}
case ConnectedAccountProvider.GOOGLE: {
const url = `https://mail.google.com/mail/?authuser=${connectedAccountHandle}#all/${messageThreadExternalId}`;
window.open(url, '_blank');
break;
}
case ConnectedAccountProvider.IMAP_SMTP_CALDAV:
case ConnectedAccountProvider.OIDC:
case ConnectedAccountProvider.SAML:
case null:
return;
default:
return;
}
};
const isReady = !messageChannelLoading && canReply;
return (
<HeadlessEngineCommandWrapperEffect
execute={handleExecute}
ready={isReady}
/>
);
};
@@ -0,0 +1,61 @@
import { DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultMessageThreadRecordPageLayoutId';
import { type PageLayout } from '@/page-layout/types/PageLayout';
import {
PageLayoutTabLayoutMode,
PageLayoutType,
WidgetConfigurationType,
WidgetType,
} from '~/generated-metadata/graphql';
export const DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT: PageLayout = {
__typename: 'PageLayout',
id: DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID,
name: 'Default Message Thread Layout',
type: PageLayoutType.RECORD_PAGE,
objectMetadataId: null,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
tabs: [
{
__typename: 'PageLayoutTab',
applicationId: '',
id: 'message-thread-tab-home',
title: 'Home',
icon: 'IconHome',
position: 100,
layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
pageLayoutId: DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID,
isOverridden: false,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
widgets: [
{
__typename: 'PageLayoutWidget',
id: 'message-thread-widget-email-thread',
pageLayoutTabId: 'message-thread-tab-home',
title: 'Thread',
type: WidgetType.EMAIL_THREAD,
objectMetadataId: null,
gridPosition: {
__typename: 'GridPosition',
row: 0,
column: 0,
rowSpan: 12,
columnSpan: 12,
},
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
viewId: null,
},
isOverridden: false,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
},
],
},
],
};
@@ -0,0 +1,2 @@
export const DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID =
'default-message-thread-page-layout';
@@ -159,6 +159,9 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
... on EmailsConfiguration {
configurationType
}
... on EmailThreadConfiguration {
configurationType
}
... on FieldConfiguration {
configurationType
fieldDisplayMode
@@ -1,5 +1,7 @@
import { DEFAULT_COMPANY_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultCompanyRecordPageLayout';
import { DEFAULT_COMPANY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultCompanyRecordPageLayoutId';
import { DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultMessageThreadRecordPageLayout';
import { DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultMessageThreadRecordPageLayoutId';
import { DEFAULT_NOTE_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultNoteRecordPageLayout';
import { DEFAULT_NOTE_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultNoteRecordPageLayoutId';
import { DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultOpportunityRecordPageLayout';
@@ -42,6 +44,8 @@ const getDefaultLayoutById = (layoutId: string): PageLayout => {
return DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT;
case DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID:
return DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT;
case DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID:
return DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT;
case DEFAULT_RECORD_PAGE_LAYOUT_ID:
default:
return DEFAULT_RECORD_PAGE_LAYOUT;
@@ -57,7 +61,8 @@ const isDefaultLayoutId = (layoutId: string): boolean =>
layoutId === DEFAULT_TASK_RECORD_PAGE_LAYOUT_ID ||
layoutId === DEFAULT_WORKFLOW_PAGE_LAYOUT_ID ||
layoutId === DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID ||
layoutId === DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID;
layoutId === DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID ||
layoutId === DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID;
export const useBasePageLayout = (
pageLayoutId: string,
@@ -1,5 +1,6 @@
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { DEFAULT_COMPANY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultCompanyRecordPageLayoutId';
import { DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultMessageThreadRecordPageLayoutId';
import { DEFAULT_NOTE_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultNoteRecordPageLayoutId';
import { DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultOpportunityRecordPageLayoutId';
import { DEFAULT_PERSON_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultPersonRecordPageLayoutId';
@@ -20,6 +21,8 @@ const OBJECT_NAME_TO_DEFAULT_LAYOUT_ID: Record<string, string> = {
[CoreObjectNameSingular.WorkflowVersion]:
DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.WorkflowRun]: DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.MessageThread]:
DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT_ID,
};
export const getDefaultRecordPageLayoutId = ({
@@ -1,5 +1,6 @@
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
import { CalendarWidget } from '@/page-layout/widgets/calendar/components/CalendarWidget';
import { EmailThreadWidget } from '@/page-layout/widgets/email-thread/components/EmailThreadWidget';
import { EmailWidget } from '@/page-layout/widgets/emails/components/EmailWidget';
import { FieldRichTextWidgetRenderer } from '@/page-layout/widgets/field-rich-text/components/FieldRichTextWidgetRenderer';
import { FieldWidget } from '@/page-layout/widgets/field/components/FieldWidget';
@@ -77,6 +78,9 @@ export const WidgetContentRenderer = ({
case WidgetType.RECORD_TABLE:
return <RecordTableWidgetRenderer widget={widget} />;
case WidgetType.EMAIL_THREAD:
return <EmailThreadWidget widget={widget} />;
default:
return null;
}
@@ -111,11 +111,14 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => {
// TODO: when we have more widgets without headers, we should use a more generic approach to hide the header
// each widget type could have metadata (e.g., hasHeader: boolean or headerMode: 'always' | 'editOnly' | 'never')
const isRichTextWidget = widget.type === WidgetType.STANDALONE_RICH_TEXT;
const hideRichTextHeader = isRichTextWidget && !isPageLayoutInEditMode;
const isHeaderHiddenInViewMode =
widget.type === WidgetType.STANDALONE_RICH_TEXT ||
widget.type === WidgetType.EMAIL_THREAD;
const hideHeaderInViewMode =
isHeaderHiddenInViewMode && !isPageLayoutInEditMode;
const showHeader =
layoutMode !== PageLayoutTabLayoutMode.CANVAS && !hideRichTextHeader;
layoutMode !== PageLayoutTabLayoutMode.CANVAS && !hideHeaderInViewMode;
const handleClick = () => {
handleEditWidget({
@@ -3,23 +3,25 @@ import { useState } from 'react';
import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage';
import { type EmailThreadMessageWithSender } from '@/activities/emails/types/EmailThreadMessageWithSender';
import { Button } from 'twenty-ui/input';
import { t } from '@lingui/core/macro';
import { IconArrowsVertical } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledButtonContainer = styled.div`
border-bottom: 1px solid ${themeCssVariables.border.color.light};
padding: 16px 24px;
padding: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[6]};
`;
export const SidePanelMessageThreadIntermediaryMessages = ({
export const EmailThreadIntermediaryMessages = ({
messages,
}: {
messages: EmailThreadMessageWithSender[];
}) => {
const [areMessagesOpen, setAreMessagesOpen] = useState(false);
const messagesLength = messages.length;
if (messages.length === 0) {
if (messagesLength === 0) {
return null;
}
@@ -37,7 +39,7 @@ export const SidePanelMessageThreadIntermediaryMessages = ({
<StyledButtonContainer>
<Button
Icon={IconArrowsVertical}
title={`${messages.length} email${messages.length > 1 ? 's' : ''}`}
title={t`${messagesLength} emails`}
size="small"
onClick={() => setAreMessagesOpen(true)}
/>
@@ -0,0 +1,91 @@
import { styled } from '@linaria/react';
import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader';
import { EmailLoader } from '@/activities/emails/components/EmailLoader';
import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage';
import { useEmailThread } from '@/activities/emails/hooks/useEmailThread';
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
import { EmailThreadIntermediaryMessages } from '@/page-layout/widgets/email-thread/components/EmailThreadIntermediaryMessages';
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
import { t } from '@lingui/core/macro';
const StyledWrapper = styled.div`
display: flex;
flex-direction: column;
width: 100%;
`;
const StyledContainer = styled.div`
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow-y: auto;
`;
type EmailThreadWidgetProps = {
widget: PageLayoutWidget;
};
export const EmailThreadWidget = ({
widget: _widget,
}: EmailThreadWidgetProps) => {
const targetRecord = useTargetRecord();
const { thread, messages, fetchMoreMessages, threadLoading } = useEmailThread(
targetRecord.id,
);
const messagesCount = messages.length;
const is5OrMoreMessages = messagesCount >= 5;
const firstMessages = messages.slice(
0,
is5OrMoreMessages ? 2 : messagesCount - 1,
);
const intermediaryMessages = is5OrMoreMessages
? messages.slice(2, messagesCount - 1)
: [];
const lastMessage = messages[messagesCount - 1];
if (threadLoading || !thread || !messages.length) {
return (
<StyledWrapper>
<StyledContainer>
<EmailLoader loadingText={t`Loading thread`} />
</StyledContainer>
</StyledWrapper>
);
}
return (
<StyledWrapper>
<StyledContainer>
{
<>
{firstMessages.map((message) => (
<EmailThreadMessage
key={message.id}
sender={message.sender}
participants={message.messageParticipants}
body={message.text}
sentAt={message.receivedAt}
/>
))}
<EmailThreadIntermediaryMessages messages={intermediaryMessages} />
<EmailThreadMessage
key={lastMessage.id}
sender={lastMessage.sender}
participants={lastMessage.messageParticipants}
body={lastMessage.text}
sentAt={lastMessage.receivedAt}
isExpanded
/>
<CustomResolverFetchMoreLoader
loading={threadLoading}
onLastRowVisible={fetchMoreMessages}
/>
</>
}
</StyledContainer>
</StyledWrapper>
);
};
@@ -1,8 +1,5 @@
import { type CalendarChannel } from '@/accounts/types/CalendarChannel';
import { CoreObjectNameSingular, FeatureFlagKey } from 'twenty-shared/types';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { UPDATE_CALENDAR_CHANNEL } from '@/settings/accounts/graphql/mutations/updateCalendarChannel';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useMutation } from '@apollo/client/react';
import { SettingsAccountsEventVisibilitySettingsCard } from '@/settings/accounts/components/SettingsAccountsCalendarVisibilitySettingsCard';
import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle';
@@ -30,25 +27,12 @@ type SettingsAccountsCalendarChannelDetailsProps = {
export const SettingsAccountsCalendarChannelDetails = ({
calendarChannel,
}: SettingsAccountsCalendarChannelDetailsProps) => {
const featureFlagsMap = useFeatureFlagsMap();
const isMigrated =
featureFlagsMap[FeatureFlagKey.IS_CONNECTED_ACCOUNT_MIGRATED] ?? false;
const { updateOneRecord } = useUpdateOneRecord();
const [updateMetadataChannel] = useMutation(UPDATE_CALENDAR_CHANNEL);
const updateChannel = (update: Record<string, unknown>) => {
if (isMigrated) {
updateMetadataChannel({
variables: { input: { id: calendarChannel.id, update } },
});
} else {
updateOneRecord({
objectNameSingular: CoreObjectNameSingular.CalendarChannel,
idToUpdate: calendarChannel.id,
updateOneRecordInput: update,
});
}
updateMetadataChannel({
variables: { input: { id: calendarChannel.id, update } },
});
};
const handleVisibilityChange = (value: CalendarChannelVisibility) => {
@@ -5,10 +5,7 @@ import {
type MessageChannelContactAutoCreationPolicy,
type MessageFolderImportPolicy,
} from '@/accounts/types/MessageChannel';
import { CoreObjectNameSingular, FeatureFlagKey } from 'twenty-shared/types';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { UPDATE_MESSAGE_CHANNEL } from '@/settings/accounts/graphql/mutations/updateMessageChannel';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useMutation } from '@apollo/client/react';
import { SettingsAccountsMessageAutoCreationCard } from '@/settings/accounts/components/SettingsAccountsMessageAutoCreationCard';
import { SettingsAccountsMessageFolderCard } from '@/settings/accounts/components/SettingsAccountsMessageFolderCard';
@@ -43,25 +40,12 @@ const StyledDetailsContainer = styled.div`
export const SettingsAccountsMessageChannelDetails = ({
messageChannel,
}: SettingsAccountsMessageChannelDetailsProps) => {
const featureFlagsMap = useFeatureFlagsMap();
const isMigrated =
featureFlagsMap[FeatureFlagKey.IS_CONNECTED_ACCOUNT_MIGRATED] ?? false;
const { updateOneRecord } = useUpdateOneRecord();
const [updateMetadataChannel] = useMutation(UPDATE_MESSAGE_CHANNEL);
const updateChannel = (update: Record<string, unknown>) => {
if (isMigrated) {
updateMetadataChannel({
variables: { input: { id: messageChannel.id, update } },
});
} else {
updateOneRecord({
objectNameSingular: CoreObjectNameSingular.MessageChannel,
idToUpdate: messageChannel.id,
updateOneRecordInput: update,
});
}
updateMetadataChannel({
variables: { input: { id: messageChannel.id, update } },
});
};
const handleVisibilityChange = (value: MessageChannelVisibility) => {

Some files were not shown because too many files have changed in this diff Show More