Compare commits

...
32 Commits
Author SHA1 Message Date
MarieandGitHub 86df188e83 [fix] Fix switch view type from "Layout" switcher (#16382)
In this previous work aiming at eliminating the creation of viewGroups
being separated from the views, I removed the creation of viewGroups
from the FE at view creation, but forgot to do it at view update when
the user chooses "change Layout" option (from Table/Kanban/Calendar to
another).

In this PR
- I removed creation, deletion and destroy of viewGroups from
usePersistViewGroupRecords. I left update because it useful for
visibility and position
- since usePersistViewGroups record was also handling optimistic, I
moved optimistic logic to a new hook useViewsSideEffectsOnViewGroups. I
realized that so far we optimistic is only useful for creation. For the
update though we do need to compute the view groups that will be created
to be able to call loadRecordIndexState, so I created a function for
that, but I did not seek to perform real optimistic, with writing and
deleting groups from the cache as it was a bit heavier and not in use
for now and I want to merge this asap as it fixes the creation of
viewGroups.
2025-12-08 15:05:05 +01:00
Charles BochetandGitHub 2790d5dd93 Message fixes (#16389)
In this PR:
- add more logs to troubleshoot issues in production
- use messageChannelSyncStatus in messageSync service instead of making
a manual update
2025-12-08 14:56:43 +01:00
neo773andGitHub 5f4c7e016c refactor imap gql resolver (#16375) 2025-12-08 14:54:24 +01:00
Baptiste DevessierandGitHub 51c0a8dd86 [Page layouts] Sync tabs with URL hash (#16341)
There are three identified scenarios.

## First scenario

The user uses a desktop. They click on a company, which is opened in the
side panel. They click on a tab, like "Tasks". The user chooses to open
the record in fullscreen. The "Tasks" tab is opened by default in the
fullscreen record page.

If the user refreshes the page, the default tab is shown: "Timeline".
**This was the behavior on the show pages, and I kept it.** If we wanted
to show the "Tasks" tab here, we would have to put the id of the "Tasks"
tab in the URL hash when we open the record in fullscreen and an active
tab id is already set.


https://github.com/user-attachments/assets/205776ac-9ad7-4e79-af9a-6b44360a5d77

## Second scenario

The user uses a desktop or a mobile device and interacts with a company
record. They click on a tab. If they refresh, the selected tab will be
displayed by default.

### Desktop


https://github.com/user-attachments/assets/d4e1908b-a591-42f6-bb82-5aec592e2778

### Mobile


https://github.com/user-attachments/assets/7bab73cc-a2ff-4ce8-9bc6-325efef2d500

## Third scenario

The user uses a desktop. They click on a dashboard, which is opened in
fullscreen mode by default. They select tabs. If they refresh, the last
selected tab is opened by default.

When the user turns edit mode on, **the url hash is removed**. The last
selected tab remains selected. If the user selects another tab, the url
hash isn't set, but the newly selected tab is displayed correctly. If
the user saves their changes, the selected tab remains selected.
However, if they refresh the page, the default tab replaces the
previously selected tab.

Not setting the url hash when editing a page layout simplifies the code.
I'm okay with this tradeoff as the feature is primarily meant to let
users share specific tabs of their records.

**This behavior will also be used for record page layout once edit mode
is supported.**


https://github.com/user-attachments/assets/869657a1-6895-4ade-816c-972c77aaab9e

Closes https://github.com/twentyhq/core-team-issues/issues/1784
2025-12-08 10:47:46 +01:00
martmullandGitHub 7f1e69740a 1895 extensibility v1 application tokens (#16365)
First PR to implement application tokens
- add new application role in twenty-server
- move duplicated constants and types to twenty-shared
- will  add role configuration utils into twenty-sdk in another PR
2025-12-08 10:42:46 +01:00
Félix MalfaitandGitHub 1f9a6b067a fix: make impersonation audit logging non-blocking (#16390)
## Summary

This PR makes the Clickhouse audit logging in the impersonation flow
**non-blocking** (fire-and-forget).

## Problem

When the Clickhouse server is unavailable or slow, the impersonation
feature becomes blocked because all audit logging calls use `await`,
causing the entire impersonation flow to hang.

## Solution

Remove the `await` keyword from all audit logging calls in the
impersonation flow. The `ClickHouseService.insert()` method already
handles errors internally (catches and logs them), so there's no risk of
unhandled promise rejections.

## Changes

- **`impersonation.service.ts`**: 4 audit calls made non-blocking
- **`auth.resolver.ts`**: 5 audit calls made non-blocking  
- **`auth.service.ts`**: 2 audit calls made non-blocking

## Testing

- Impersonation flow continues to work when Clickhouse is available
- Impersonation flow no longer blocks when Clickhouse is unavailable
2025-12-08 08:48:44 +00:00
Paul RastoinandGitHub 3e57aa14d3 Refactor page layout tab and widgets migration (#16367)
# Introduction
Making columns nullable instead of required + metadata on the fly
migration in typeorm migration that could affect other breaking change
migrations to be run
2025-12-06 10:23:24 +01:00
Félix MalfaitandGitHub 223082a4da refactor(twenty-server): consolidate AI tool provider architecture (#16355)
## Summary

Consolidates the AI tool provider architecture by creating a single
`ToolProviderService` as the entry point for all tool generation. This
removes multiple intermediate services and simplifies the codebase.

## Changes

### New Architecture
- **`ToolProviderService`**: Single service for all tool generation
with:
  - `getTools(spec)` - Get tools by category with permissions
  - `getToolByType(type)` - Get specific tool for workflow execution
  
- **`ToolCategory` enum**: Declarative specification of tool types:
  - `DATABASE_CRUD` - Record CRUD operations
  - `ACTION` - HTTP requests, email sending, article search
  - `WORKFLOW` - Workflow management tools
  - `METADATA` - Object/field metadata tools
  - `NATIVE_MODEL` - Model-specific tools (e.g., web search)

- **`ToolSpecification` type**: Clean API for requesting tools with
permissions

### Removed
- `AiToolsModule` - No longer needed
- `ToolService` - Logic inlined into ToolProviderService
- `ToolAdapterService` - Logic inlined into ToolProviderService
- `ToolRegistryService` - Logic inlined into ToolProviderService

### Updated
- All consumers (agents, chat, MCP, workflows) now use
`ToolProviderService`
- Test files updated accordingly

## Stats
- **547 insertions, 1146 deletions** (net ~600 lines removed)
- 4 services deleted
- 1 module deleted

## Testing
- [x] Typecheck passes
- [x] Lint passes
2025-12-06 06:51:47 +01:00
nitinandGitHub 43ed4963d6 [Dashboards] Improve tooltip animations (#16357)
before - 


https://github.com/user-attachments/assets/069a8737-fcc9-4186-bdbf-e9ed0dfa41a8


after - 


https://github.com/user-attachments/assets/dbc8604c-dda0-46a9-a67b-f59cc91d7f53
2025-12-05 18:28:26 +01:00
Abdul RahmanandGitHub b706664c99 Show add step button on trigger node without hover (#16361)
https://github.com/user-attachments/assets/3407bbea-356b-4508-b931-27b45818a339

Closes #14136
2025-12-05 18:28:13 +01:00
Paul RastoinandGitHub c8f541618d Refactor validate build and run for configuration to be less verbose and more reliable (#16343)
# Introduction
Refactored the api `validateBuildAndRunWorkspaceMigration` to be require
less configuration but to infer required args dynamically depending on
provided metadata maps to compare

## `inferDeletionFromMissingEntities`
Is not dynamically computed avoiding any miss configuration issue and
any missleading devxp

## Maps computation

Making only one call to redis to build both dependency and to be
compared entity maps. It does not matter to avoid passing a about to
compared flat entity maps to could also be a depedency, it's handled
directly in the builder setup optimistic cache logic

Please note that the flat maps used for the service input transpilation
might differ from the one that we will dynamically compute and inject in
the builder. Leading to do 2 redis calls but also race condition prone
validation error
We prefer that this occurs at the builder rather than at the runner
level as the pg instance is not cache and reflect the real state of a
given workspace
In a nutshell, there's a possible race condition between cache
invalidation and computation in both service input transpilers and
builder but we're totally ok with that
2025-12-05 15:41:56 +00:00
fee3e6b7a1 fix folder actions (#16344)
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-12-05 16:19:50 +01:00
Thomas TrompetteandGitHub de4e78e5b2 Fix workflow relation variables (#16362)
display many to one relations instead of one to many
2025-12-05 16:11:37 +01:00
Baptiste DevessierandGitHub 2466d81ace [Record Page Layouts] Pin record header (#16339)
https://github.com/user-attachments/assets/df988bf2-d2d6-49a4-b062-bc7ec49e1fad

Closes https://github.com/twentyhq/core-team-issues/issues/1806
2025-12-05 16:10:08 +01:00
MarieandGitHub 58b8b49d1d Fix flaky storybook test (#16358)
RecordTable story was flaky with this kind of error
[(1)](https://www.apollographql.com/docs/react/errors#%7B%22version%22%3A%223.13.8%22%2C%22message%22%3A13%2C%22args%22%3A%5B%22addressStreet2%22%2C%22%7B%5Cn%20%20%5C%22__typename%5C%22%3A%20%5C%22Address%5C%22%2C%5Cn%20%20%5C%22addressLine1%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%5C%22addressLine2%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%5C%22addressCity%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%5C%22addressState%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%5C%22addressCountry%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%5C%22addressPostcode%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%5C%22addressLat%5C%22%3A%20null%2C%5Cn%20%20%5C%22addressLng%5C%22%3A%20null%5Cn%7D%22%5D%7D):
_Missing field 'addressStreet2' while writing result { "typename":
"Address", "addressLine1": "", "addressLine2": "", "addressCity": "",
"addressState": "", "addressCountry": "", "addressPostcode": "",
"addressLat": null, "addressLng": null }_ or
[(2)](https://www.apollographql.com/docs/react/errors#%7B%22version%22%3A%223.13.8%22%2C%22message%22%3A13%2C%22args%22%3A%5B%22deletedAt%22%2C%22%7B%5Cn%20%20%5C%22__typename%5C%22%3A%20%5C%22Company%5C%22%2C%5Cn%20%20%5C%22id%5C%22%3A%20%5C%2220202020-5d81-46d6-bf83-f7fd33ea6102%5C%22%2C%5Cn%20%20%5C%22employees%5C%22%3A%20null%2C%5Cn%20%20%5C%22createdAt%5C%22%3A%20%5C%222025-01-06T08%3A30%3A15.412Z%5C%22%2C%5Cn%20%20%5C%22updatedAt%5C%22%3A%20%5C%222025-01-06T14%3A45%3A22.412Z%5C%22%2C%5Cn%20%20%5C%22name%5C%22%3A%20%5C%22Facebook%5C%22%2C%5Cn%20%20%5C%22idealCustomerProfile%5C%22%3A%20false%2C%5Cn%20%20%5C%22accountOwner%5C%22%3A%20null%2C%5Cn%20%20%5C%22accountOwnerId%5C%22%3A%20null%2C%5Cn%20%20%5C%22domainName%5C%22%3A%20%7B%5Cn%20%20%20%20%5C%22__typename%5C%22%3A%20%5C%22Links%5C%22%2C%5Cn%20%20%20%20%5C%22primaryLinkUrl%5C%22%3A%20%5C%22https%3A%2F%2Ffacebook.com%5C%22%2C%5Cn%20%20%20%20%5C%22primaryLinkLabel%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22secondaryLinks%5C%22%3A%20%5B%5D%5Cn%20%20%7D%2C%5Cn%20%20%5C%22address%5C%22%3A%20%7B%5Cn%20%20%20%20%5C%22addressStreet1%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22addressStreet2%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22addressCity%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22addressState%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22addressCountry%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22addressPostcode%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22addressLat%5C%22%3A%20null%2C%5Cn%20%20%20%20%5C%22addressLng%5C%22%3A%20null%5Cn%20%20%7D%2C%5Cn%20%20%5C%22previousEmployees%5C%22%3A%20null%2C%5Cn%20%20%5C%22annualRecurringRevenue%5C%22%3A%20%7B%5Cn%20%20%20%20%5C%22__typename%5C%22%3A%20%5C%22Currency%5C%22%2C%5Cn%20%20%20%20%5C%22amountMicros%5C%22%3A%20null%2C%5Cn%20%20%20%20%5C%22currencyCode%5C%22%3A%20%5C%22%5C%22%5Cn%20%20%7D%2C%5Cn%20%20%5C%22position%5C%22%3A%202%2C%5Cn%20%20%5C%22xLink%5C%22%3A%20%7B%5Cn%20%20%20%20%5C%22__typename%5C%22%3A%20%5C%22Links%5C%22%2C%5Cn%20%20%20%20%5C%22primaryLinkLabel%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22primaryLinkUrl%5C%22%3A%20%5C%22%5C%22%2C%5Cn%20%20%20%20%5C%22secondaryLinks%5C%22%3A%20%5B%5D%5Cn%20%20%7D%2C%5Cn%20%20%5C%22linkedinLink%5C%22%3A%20%7B%5Cn%20%20%20%20%5C%22__typename%5C%22%3A%20%5C%22Links%5C%22%2C%5Cn%20%20%20%20%5C%22primary%22%5D%7D):
_Missing field 'deletedAt' while writing result..._

What the issue is and why is it flaky?
<img width="463" height="525" alt="image"
src="https://github.com/user-attachments/assets/af82a5ae-bce8-4e2f-a25b-b6f027082bc1"
/>
flakines may be due to timing of when the error is thrown vs when test
assertions run
2025-12-05 15:27:25 +01:00
a9033a3045 i18n - docs translations (#16359)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-12-05 15:21:01 +01:00
MarieandGitHub 7ce22d5c7e breaking (soft) - Migrate viewGroup.fieldMetadataId -> view.mainGroupByFieldMetadataId (2/3) (#16277)
Should be merged once https://github.com/twentyhq/twenty/pull/16206 has
been released + command run to prod

In this PR
- Remove usage of viewGroup.fieldMetadataId, both in BE and FE states. 
- But we still need to properly populate it until we fully remove
viewGroup.fieldMetadataId from db and ORM entity (upcoming 3rd PR out of
3). fieldMetadataId was removed from CoreViewGroup type and
CreateViewGroupInput and is determined BE-side based on the associated
view's mainGroupByFieldMetadataId. **I expect this means a downtime on
viewGroup creation, until both FE and BE are deployed and cache is
flushed.** This seems acceptable to me as it only regards viewGroup
creation.
    - this information is replaced by view.mainGroupByFieldMetadataID
- Handle view group creation, update and deletion in the BE as a
side-effect of a view creation, update or deletion. Optimistic effects
are still used
- Add validation at view creation or update regarding
mainGroupByFieldMetadata

Left to do in 3rd PR
- Remove viewGroup.fieldMetadataId from db and ORM entity
- Restore feature allowing to update an existing grouped view's group by
field (already OK on BE side but need to rebuild FE optimistic)
2025-12-05 14:00:03 +00:00
17d88a074b i18n - translations (#16356)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-12-05 14:40:04 +01:00
Raphaël BosiandGitHub 077be7644c Migrate page layout widget to v2 of the API (#16323) 2025-12-05 13:04:06 +00:00
Charles BochetandGitHub 56e66315cd Fix messaging direct import (#16354)
Mainly clarifying naming (scheduleMessageImport was actually tagging as
PENDING)
+ tagging as SCHEDULED in case of direct import (we skip PENDING state)
2025-12-05 10:48:09 +01:00
Charles BochetandGitHub 10b5e156e5 Improvement on messaging (#16351)
In this PR:
- change messaging / calendar stale duration check to 30minutes (cron is
running every 1h, duration check was 1h, so evaluation was flaky)
- when temporary error (throttling), preserve syncStageStartedAt as this
is necessary to assess exponential throttling
2025-12-05 00:04:07 +01:00
Félix MalfaitandGitHub 2803292521 feat: add Metadata Builder agent for data model management (#16350)
## Summary

This PR adds a new **Metadata Builder** AI agent that specializes in
managing the workspace data model (creating objects, adding fields,
etc.).

## Changes

### New Files
- `data-model-manager-role.ts` - New standard role with `DATA_MODEL`
permission flag
- `metadata-builder-agent.ts` - New standard agent for data model
management

### Modified Files
- **ChatToolsProviderService**: Refactored to consolidate all
permission-based tools into a single `getChatTools()` method. Now
injects both workflow tools and metadata tools based on permissions.
- **AgentChatRoutingService**: Updated to use the new consolidated
`getChatTools()` method
- **AiChatModule**: Added imports for `ObjectMetadataModule` and
`FieldMetadataModule`
- **Router system prompt**: Added metadata-builder agent selection rules
with clear distinction between schema operations vs data operations
- **Metadata tools factories**: Improved error messages to show detailed
validation errors instead of generic messages

### Refactoring
- Renamed `index.ts` files to `standard-agent-definitions.ts` and
`standard-role-definitions.ts` to follow naming conventions
- Renamed exports from `standardAgentDefinitions` to
`STANDARD_AGENT_DEFINITIONS` (SCREAMING_SNAKE_CASE)

## Key Features

1. **Metadata Builder Agent** can:
   - Create new custom objects
   - Add fields to existing objects
   - Update object and field properties
   - Create relations between objects

2. **Permission-based tool injection**: Tools are automatically injected
based on the `DATA_MODEL` permission flag

3. **Improved routing**: The router now correctly distinguishes between:
   - "Create an object called Project" → metadata-builder (schema)
   - "Create a company called Acme" → data-manipulator (data)

4. **Better error messages**: Validation errors now show detailed
messages like:
   ```
   Validation errors:
   [objectMetadata] Name must be in camelCase format
   [objectMetadata] Label is required
   ```
2025-12-04 23:26:29 +01:00
Félix MalfaitandGitHub 34d7d82099 refactor(mcp): call metadata services directly instead of REST layer (#16349)
## Summary

Refactors MCP metadata tools to call underlying services directly
instead of going through the REST layer. This makes MCP a pure
presentation layer.

### Changes

**Created:**
-
`packages/twenty-server/src/engine/metadata-modules/metadata-tools/metadata-tools.module.ts`
- Module that exports MetadataToolsFactory
-
`packages/twenty-server/src/engine/metadata-modules/metadata-tools/services/metadata-tools.factory.ts`
- Factory that generates 8 metadata tools using Zod schemas:
- `get-object-metadata`, `create-object-metadata`,
`update-object-metadata`, `delete-object-metadata`
- `get-field-metadata`, `create-field-metadata`,
`update-field-metadata`, `delete-field-metadata`

**Modified:**
-
`packages/twenty-server/src/engine/api/mcp/services/mcp-metadata.service.ts`
- Uses new factory instead of REST-based services
- `packages/twenty-server/src/engine/api/mcp/mcp.module.ts` - Imports
MetadataToolsModule, removes old service imports

**Deleted:**
-
`packages/twenty-server/src/engine/api/mcp/services/tools/create.tools.service.ts`
-
`packages/twenty-server/src/engine/api/mcp/services/tools/update.tools.service.ts`
-
`packages/twenty-server/src/engine/api/mcp/services/tools/delete.tools.service.ts`
-
`packages/twenty-server/src/engine/api/mcp/services/tools/get.tools.service.ts`
-
`packages/twenty-server/src/engine/api/mcp/services/tools/mcp-metadata-tools.service.ts`

### Architecture Improvement

**Before:**
```
MCP Tool → MetadataQueryBuilderFactory → RestApiService → GraphQL API → Service
```

**After:**
```
MCP Tool → Service (ObjectMetadataService / FieldMetadataService)
```

This follows the pattern established by `direct-record-tools.factory.ts`
and workflow tools.
2025-12-04 22:21:16 +01:00
aa0471ca1f i18n - translations (#16348)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-12-04 21:21:31 +01:00
Félix MalfaitandGitHub 9cecbaebc3 refactor(workflow-tools): reorganize to one file per tool with co-located schemas (#16313)
## Summary

Reorganizes workflow tools to improve maintainability and
discoverability by having one file per tool with co-located input
schemas.

## Changes

- Create individual tool files in `tools/` directory (11 files)
- Co-locate input schemas with their tool implementations
- Add shared types file for dependencies and context
- Simplify workspace service to aggregate tool factories
- Remove centralized `schemas/` directory

## New Structure

```
workflow-tools/
├── services/
│   └── workflow-tool.workspace-service.ts
├── tools/
│   ├── activate-workflow-version.tool.ts
│   ├── compute-step-output-schema.tool.ts
│   ├── create-complete-workflow.tool.ts
│   ├── create-draft-from-workflow-version.tool.ts
│   ├── create-workflow-version-edge.tool.ts
│   ├── create-workflow-version-step.tool.ts
│   ├── deactivate-workflow-version.tool.ts
│   ├── delete-workflow-version-edge.tool.ts
│   ├── delete-workflow-version-step.tool.ts
│   ├── update-workflow-version-positions.tool.ts
│   └── update-workflow-version-step.tool.ts
├── types/
│   └── workflow-tool-dependencies.type.ts
└── workflow-tools.module.ts
```

## Benefits

- **Co-location**: Schema and tool logic are in the same file
- **Single responsibility**: Each file handles one tool
- **Easier maintenance**: Changes to a tool only touch one file
- **Better discoverability**: File names match tool names
2025-12-04 21:06:49 +01:00
WeikoandGitHub 1991ee850e Fix seeding perf + batch role targets creation (#16337) 2025-12-04 20:29:48 +01:00
e653385485 i18n - docs translations (#16345)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-12-04 19:22:39 +01:00
ddece3aac8 i18n - translations (#16342)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-12-04 19:01:28 +01:00
nitinandGitHub 8f756937ae [Dashboards] Pie chart custom tooltip (#16318)
closes https://github.com/twentyhq/core-team-issues/issues/1884

and https://discord.com/channels/1130383047699738754/1443679780414427267


before - 


https://github.com/user-attachments/assets/db19657f-d7d3-4965-9b88-83e5829d3942


after -


https://github.com/user-attachments/assets/d88ec686-0298-4b5f-a214-03e8d8169e7d
2025-12-04 17:22:21 +00:00
aede5bab34 i18n - translations (#16338)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-12-04 18:21:26 +01:00
Paul RastoinandGitHub 28cdb02fbb Twenty standard application Objects and fields as allFlatEntityMaps ID non-agnostic (#16298)
# Introduction

Related to https://github.com/twentyhq/core-team-issues/issues/1995
This PR introduces the basis of the `twentyStandard` application as code
on demand, it's highly tied to `ids` where it will becomes workspace
agnostic following the builder and runner `universalIdentifier` refactor
later.

The goal here to allow computing the `allFlatEntityMaps` `to` of the
`twentyStandard` application on a empty workspace ( workspace creation
). Allowing installing the twenty standard app through a workspace
migration instead of passing by the sync metadata

Nothing done will be run in production for the moment if it's not the
small validation refactor we've introduced

Please note that everything introduced here will be replaced at some
point by a twenty app instance when the twenty sdk is mature enough to
handle of the edge cases we need here

## How we've proceeded
We've been iterating over every workspace entity both objects and their
fields, and transpiled them to flatEntity.
Being sure we migrate the defaultValue, settings and so on accordingly.
We've also compute all the ids in prior of the whole entities
computation so we don't face any hoisting issue.

## Current state
At the moment only handling all of the 29 standard objects and their
fields
Settings a unique universalIdentifier for all of them

Will come views, agent role targets and so on later

## `workspace:compute-twenty-standard-migration` command
This command allow generating a workspace migration that will result in
installing the twenty standard app in an empty workspace
It's temporary and aims to allow debugging for the moment we might not
keep it in the future as it is right now
It contains debug writeFileSync which is expected no worries greptile

## `LabelFieldMetadataIdentifierId`
Small refactor allowing defining the label identifier field metadata id
of a uuid field metadata type for system object, as some of our standard
object don't have a name field and don't aim to
Also please note that we might remove this build options later in the
sake of the currently installed universal identifier application that we
could compare with the deterministic twenty standard one

## `runFlatFieldMetadataValidators`
Deprecated this pattern which was redundant and not v2 friendly pattern

## Current errors that will address in upcoming PR
Current standard objects and fields metadata does not pass the
validation that we have in place, as historically the sync metadata
would directly consume the repositories and would just ignore the
validation. This is about to change.
Will handle the below errors in dedicated PRs as they will required
upgrade commands in order to migrate the data, or will handle that from
the sync metadata instead still to be determined but nothing critical
here

- camel case field metadata name
- options label invalid format

```json
{
  "status": "fail",
  "report": {
    "fieldMetadata": [
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Name should be in camelCase",
            "userFriendlyMessage": {
              "id": "P+jdmX",
              "message": "Name should be in camelCase"
            },
            "value": "iCalUID"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "68dd83cd-92c8-4233-bb28-47939bab6124",
          "name": "iCalUID",
          "objectMetadataId": "11c16ab6-9176-439e-a2db-a12c5a58a524"
        },
        "type": "create_field"
      },
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"email\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "email"
              }
            },
            "value": "email"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"sms\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "sms"
              }
            },
            "value": "sms"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "e3caaf2a-e07d-4146-8dfc-9eef904e82c9",
          "name": "type",
          "objectMetadataId": "4b777de5-4c7b-4af4-9b92-655c0f87512b"
        },
        "type": "create_field"
      },
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"incoming\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "incoming"
              }
            },
            "value": "incoming"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"outgoing\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "outgoing"
              }
            },
            "value": "outgoing"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "d96233a4-93be-45ea-9548-3b50f3c700cf",
          "name": "direction",
          "objectMetadataId": "480a648a-d2e5-482a-992f-ef053e1b4bb0"
        },
        "type": "create_field"
      },
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"from\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "from"
              }
            },
            "value": "from"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"to\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "to"
              }
            },
            "value": "to"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"cc\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "cc"
              }
            },
            "value": "cc"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"bcc\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "bcc"
              }
            },
            "value": "bcc"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "961c598e-67c3-452d-8bb2-b92c0bc64404",
          "name": "role",
          "objectMetadataId": "8af8a13c-ff97-4cd3-b70d-52a7dc2924b4"
        },
        "type": "create_field"
      },
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Label must not contain a comma",
            "userFriendlyMessage": {
              "id": "k731jp",
              "message": "Label must not contain a comma"
            },
            "value": "Commas and dot (1,234.56)"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Label must not contain a comma",
            "userFriendlyMessage": {
              "id": "k731jp",
              "message": "Label must not contain a comma"
            },
            "value": "Spaces and comma (1 234,56)"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Label must not contain a comma",
            "userFriendlyMessage": {
              "id": "k731jp",
              "message": "Label must not contain a comma"
            },
            "value": "Dots and comma (1.234,56)"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "7fa20caf-2597-42e3-84e5-15a91b125b9b",
          "name": "numberFormat",
          "objectMetadataId": "a6974302-9e72-461c-aa09-9390f4ff16fc"
        },
        "type": "create_field"
      }
    ],
    "objectMetadata": [],
    "view": [],
    "viewField": [],
    "viewGroup": [],
    "index": [],
    "serverlessFunction": [],
    "cronTrigger": [],
    "databaseEventTrigger": [],
    "routeTrigger": [],
    "viewFilter": [],
    "role": [],
    "roleTarget": [],
    "agent": []
  }
}
```
2025-12-04 17:39:12 +01:00
b2d785de4b Page layout tab v2 (#16319)
# Introduction
Migrating `pageLayoutTab` to the v2 engine
- Types and constants
- Builder and validate
- Runner

Introduced a new `StrictSyncableEntity` that enforces that
`universalIdentifier` and `applicationId` are defined
As these entities are brand new we could enforce this rule already
This still requires a migration command to associate the existing
entities to custom workspace application instance and define
universalIdentifier

Handled retro-comp of the migration through a migration as upgrade
command fallback

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
2025-12-04 17:37:16 +01:00
823 changed files with 24644 additions and 7472 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "create-twenty-app",
"version": "0.1.3",
"version": "0.2.0",
"description": "Command-line interface to create Twenty application",
"main": "dist/cli.cjs",
"bin": "dist/cli.cjs",
@@ -127,7 +127,7 @@ const createPackageJson = async ({
auth: 'twenty auth login',
},
dependencies: {
'twenty-sdk': '0.1.3',
'twenty-sdk': '0.2.0',
},
devDependencies: {
'@types/node': '^24.7.2',
@@ -115,6 +115,9 @@ Figma プラットフォームの学習に関するより包括的な詳細と
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
## コラボレーション
@@ -158,7 +158,7 @@ SSLHTTPS)は、特定のブラウザ機能が正しく動作するために
2. **.env ファイルを更新**
.env`ファイルを開き、`SERVER_URL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`を更新します:
.env`ファイルを開き、`SERVER_URL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`を更新します:
```ini
SERVER_URL=http(s)://your-domain-or-ip:your-port
@@ -30,7 +30,7 @@ Twentyは、日常をサポートする最適なデータモデルを形成す
既存のオブジェクトの特性に過ぎないもの(例:会社の「業種」や機会の「ステータス」)はフィールドにします。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。
**3. 単独で存在する場合には新しいオブジェクトを作成してください。**
概念が独自のライフサイクル、プロパティ、または関係を持つ場合、それは通常オブジェクトに値します。 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば:
概念が独自のライフサイクル、プロパティ、または関係を持つ場合、それは通常オブジェクトに値します。 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば:
- **プロジェクト**:独自の期限、所有者、タスクを持つもの
- **サブスクリプション**:会社、製品、請求書を結ぶもの
@@ -45,8 +45,9 @@ sectionInfo: 配置您的Twenty工作空间设置和偏好
刪除您的帳號將永久移除您對所有工作空間的訪問。
刪除您的帳號將永久移除您對所有工作空間的訪問。 此操作無法撤銷,您將失去所有工作空間權限,如您只想退出特定的團隊,應考慮退出個別的工作空間。 刪除您的帳號將永久移除您對所有工作空間的訪問。
刪除您的帳號將永久移除您對所有工作空間的訪問。 此操作無法撤銷,您將失去所有工作空間權限,如您只想退出特定的團隊,應考慮退出個別的工作空間。
</Warning> 刪除您的帳號將永久移除您對所有工作空間的訪問。
</Warning> 刪除您的帳號將永久移除您對所有工作空間的訪問。
刪除您的帳號將永久移除您對所有工作空間的訪問。 此操作無法撤銷,您將失去所有工作空間權限,如您只想退出特定的團隊,應考慮退出個別的工作空間。
</Warning>
要删除您的帐户:
@@ -753,7 +753,6 @@ export type CoreViewGroup = {
__typename?: 'CoreViewGroup';
createdAt: Scalars['DateTime'];
deletedAt?: Maybe<Scalars['DateTime']>;
fieldMetadataId: Scalars['UUID'];
fieldValue: Scalars['String'];
id: Scalars['UUID'];
isVisible: Scalars['Boolean'];
@@ -905,6 +904,7 @@ export type CreateRoleInput = {
canAccessAllTools?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToAgents?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApiKeys?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApplications?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToUsers?: InputMaybe<Scalars['Boolean']>;
canDestroyAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
canReadAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
@@ -963,7 +963,6 @@ export type CreateViewFilterInput = {
};
export type CreateViewGroupInput = {
fieldMetadataId: Scalars['UUID'];
fieldValue: Scalars['String'];
id?: InputMaybe<Scalars['UUID']>;
isVisible?: InputMaybe<Scalars['Boolean']>;
@@ -3796,6 +3795,7 @@ export type Role = {
objectPermissions?: Maybe<Array<ObjectPermission>>;
permissionFlags?: Maybe<Array<PermissionFlag>>;
standardId?: Maybe<Scalars['UUID']>;
universalIdentifier?: Maybe<Scalars['UUID']>;
workspaceMembers: Array<WorkspaceMember>;
};
@@ -4360,6 +4360,7 @@ export type UpdateRolePayload = {
canAccessAllTools?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToAgents?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApiKeys?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApplications?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToUsers?: InputMaybe<Scalars['Boolean']>;
canDestroyAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
canReadAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
@@ -5573,7 +5574,7 @@ export type GetConnectedImapSmtpCaldavAccountQueryVariables = Exact<{
}>;
export type GetConnectedImapSmtpCaldavAccountQuery = { __typename?: 'Query', getConnectedImapSmtpCaldavAccount: { __typename?: 'ConnectedImapSmtpCaldavAccount', id: string, handle: string, provider: string, accountOwnerId: string, connectionParameters?: { __typename?: 'ImapSmtpCaldavConnectionParameters', IMAP?: { __typename?: 'ConnectionParametersOutput', host: string, port: number, secure?: boolean | null, password: string } | null, SMTP?: { __typename?: 'ConnectionParametersOutput', host: string, username?: string | null, port: number, secure?: boolean | null, password: string } | null, CALDAV?: { __typename?: 'ConnectionParametersOutput', host: string, username?: string | null, password: string } | null } | null } };
export type GetConnectedImapSmtpCaldavAccountQuery = { __typename?: 'Query', getConnectedImapSmtpCaldavAccount: { __typename?: 'ConnectedImapSmtpCaldavAccount', id: string, handle: string, provider: string, accountOwnerId: string, connectionParameters?: { __typename?: 'ImapSmtpCaldavConnectionParameters', IMAP?: { __typename?: 'ConnectionParametersOutput', host: string, port: number, secure?: boolean | null, username?: string | null, password: string } | null, SMTP?: { __typename?: 'ConnectionParametersOutput', host: string, username?: string | null, port: number, secure?: boolean | null, password: string } | null, CALDAV?: { __typename?: 'ConnectionParametersOutput', host: string, username?: string | null, password: string } | null } | null } };
export type CreateDatabaseConfigVariableMutationVariables = Exact<{
key: Scalars['String'];
@@ -6069,9 +6070,9 @@ export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: st
export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string };
export type ViewFragmentFragment = { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type ViewFragmentFragment = { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null };
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null };
export type ViewSortFragmentFragment = { __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string };
@@ -6080,7 +6081,7 @@ export type CreateCoreViewMutationVariables = Exact<{
}>;
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
export type CreateCoreViewFieldMutationVariables = Exact<{
input: CreateViewFieldInput;
@@ -6108,7 +6109,7 @@ export type CreateCoreViewGroupMutationVariables = Exact<{
}>;
export type CreateCoreViewGroupMutation = { __typename?: 'Mutation', createCoreViewGroup: { __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type CreateCoreViewGroupMutation = { __typename?: 'Mutation', createCoreViewGroup: { __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type CreateCoreViewSortMutationVariables = Exact<{
input: CreateViewSortInput;
@@ -6129,7 +6130,7 @@ export type CreateManyCoreViewGroupsMutationVariables = Exact<{
}>;
export type CreateManyCoreViewGroupsMutation = { __typename?: 'Mutation', createManyCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type CreateManyCoreViewGroupsMutation = { __typename?: 'Mutation', createManyCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type DeleteCoreViewMutationVariables = Exact<{
id: Scalars['String'];
@@ -6164,7 +6165,7 @@ export type DeleteCoreViewGroupMutationVariables = Exact<{
}>;
export type DeleteCoreViewGroupMutation = { __typename?: 'Mutation', deleteCoreViewGroup: { __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type DeleteCoreViewGroupMutation = { __typename?: 'Mutation', deleteCoreViewGroup: { __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type DeleteCoreViewSortMutationVariables = Exact<{
id: Scalars['String'];
@@ -6206,7 +6207,7 @@ export type DestroyCoreViewGroupMutationVariables = Exact<{
}>;
export type DestroyCoreViewGroupMutation = { __typename?: 'Mutation', destroyCoreViewGroup: { __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type DestroyCoreViewGroupMutation = { __typename?: 'Mutation', destroyCoreViewGroup: { __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type DestroyCoreViewSortMutationVariables = Exact<{
id: Scalars['String'];
@@ -6221,7 +6222,7 @@ export type UpdateCoreViewMutationVariables = Exact<{
}>;
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
export type UpdateCoreViewFieldMutationVariables = Exact<{
input: UpdateViewFieldInput;
@@ -6250,7 +6251,7 @@ export type UpdateCoreViewGroupMutationVariables = Exact<{
}>;
export type UpdateCoreViewGroupMutation = { __typename?: 'Mutation', updateCoreViewGroup: { __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type UpdateCoreViewGroupMutation = { __typename?: 'Mutation', updateCoreViewGroup: { __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type UpdateCoreViewSortMutationVariables = Exact<{
id: Scalars['String'];
@@ -6263,7 +6264,7 @@ export type UpdateCoreViewSortMutation = { __typename?: 'Mutation', updateCoreVi
export type FindAllCoreViewsQueryVariables = Exact<{ [key: string]: never; }>;
export type FindAllCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
export type FindAllCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
export type FindManyCoreViewFieldsQueryVariables = Exact<{
viewId: Scalars['String'];
@@ -6291,7 +6292,7 @@ export type FindManyCoreViewGroupsQueryVariables = Exact<{
}>;
export type FindManyCoreViewGroupsQuery = { __typename?: 'Query', getCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type FindManyCoreViewGroupsQuery = { __typename?: 'Query', getCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type FindManyCoreViewSortsQueryVariables = Exact<{
viewId?: InputMaybe<Scalars['String']>;
@@ -6305,14 +6306,14 @@ export type FindManyCoreViewsQueryVariables = Exact<{
}>;
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
export type FindOneCoreViewQueryVariables = Exact<{
id: Scalars['String'];
}>;
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } | null };
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } | null };
export type FindOneCoreViewFieldQueryVariables = Exact<{
id: Scalars['String'];
@@ -6340,7 +6341,7 @@ export type FindOneCoreViewGroupQueryVariables = Exact<{
}>;
export type FindOneCoreViewGroupQuery = { __typename?: 'Query', getCoreViewGroup?: { __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } | null };
export type FindOneCoreViewGroupQuery = { __typename?: 'Query', getCoreViewGroup?: { __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null } | null };
export type FindOneCoreViewSortQueryVariables = Exact<{
id: Scalars['String'];
@@ -7142,7 +7143,6 @@ export const ViewSortFragmentFragmentDoc = gql`
export const ViewGroupFragmentFragmentDoc = gql`
fragment ViewGroupFragment on CoreViewGroup {
id
fieldMetadataId
isVisible
fieldValue
position
@@ -7165,6 +7165,7 @@ export const ViewFragmentFragmentDoc = gql`
openRecordIn
kanbanAggregateOperation
kanbanAggregateOperationFieldMetadataId
mainGroupByFieldMetadataId
anyFieldFilterValue
calendarFieldMetadataId
calendarLayout
@@ -10201,6 +10202,7 @@ export const GetConnectedImapSmtpCaldavAccountDocument = gql`
host
port
secure
username
password
}
SMTP {
+18 -17
View File
@@ -753,7 +753,6 @@ export type CoreViewGroup = {
__typename?: 'CoreViewGroup';
createdAt: Scalars['DateTime'];
deletedAt?: Maybe<Scalars['DateTime']>;
fieldMetadataId: Scalars['UUID'];
fieldValue: Scalars['String'];
id: Scalars['UUID'];
isVisible: Scalars['Boolean'];
@@ -888,6 +887,7 @@ export type CreateRoleInput = {
canAccessAllTools?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToAgents?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApiKeys?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApplications?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToUsers?: InputMaybe<Scalars['Boolean']>;
canDestroyAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
canReadAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
@@ -946,7 +946,6 @@ export type CreateViewFilterInput = {
};
export type CreateViewGroupInput = {
fieldMetadataId: Scalars['UUID'];
fieldValue: Scalars['String'];
id?: InputMaybe<Scalars['UUID']>;
isVisible?: InputMaybe<Scalars['Boolean']>;
@@ -3633,6 +3632,7 @@ export type Role = {
objectPermissions?: Maybe<Array<ObjectPermission>>;
permissionFlags?: Maybe<Array<PermissionFlag>>;
standardId?: Maybe<Scalars['UUID']>;
universalIdentifier?: Maybe<Scalars['UUID']>;
workspaceMembers: Array<WorkspaceMember>;
};
@@ -4189,6 +4189,7 @@ export type UpdateRolePayload = {
canAccessAllTools?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToAgents?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApiKeys?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApplications?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToUsers?: InputMaybe<Scalars['Boolean']>;
canDestroyAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
canReadAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
@@ -4847,9 +4848,9 @@ export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: an
export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any };
export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null };
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null };
export type ViewSortFragmentFragment = { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any };
@@ -4858,7 +4859,7 @@ export type CreateCoreViewMutationVariables = Exact<{
}>;
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
export type CreateCoreViewFieldMutationVariables = Exact<{
input: CreateViewFieldInput;
@@ -4886,7 +4887,7 @@ export type CreateCoreViewGroupMutationVariables = Exact<{
}>;
export type CreateCoreViewGroupMutation = { __typename?: 'Mutation', createCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type CreateCoreViewGroupMutation = { __typename?: 'Mutation', createCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type CreateCoreViewSortMutationVariables = Exact<{
input: CreateViewSortInput;
@@ -4907,7 +4908,7 @@ export type CreateManyCoreViewGroupsMutationVariables = Exact<{
}>;
export type CreateManyCoreViewGroupsMutation = { __typename?: 'Mutation', createManyCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type CreateManyCoreViewGroupsMutation = { __typename?: 'Mutation', createManyCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type DeleteCoreViewMutationVariables = Exact<{
id: Scalars['String'];
@@ -4942,7 +4943,7 @@ export type DeleteCoreViewGroupMutationVariables = Exact<{
}>;
export type DeleteCoreViewGroupMutation = { __typename?: 'Mutation', deleteCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type DeleteCoreViewGroupMutation = { __typename?: 'Mutation', deleteCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type DeleteCoreViewSortMutationVariables = Exact<{
id: Scalars['String'];
@@ -4984,7 +4985,7 @@ export type DestroyCoreViewGroupMutationVariables = Exact<{
}>;
export type DestroyCoreViewGroupMutation = { __typename?: 'Mutation', destroyCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type DestroyCoreViewGroupMutation = { __typename?: 'Mutation', destroyCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type DestroyCoreViewSortMutationVariables = Exact<{
id: Scalars['String'];
@@ -4999,7 +5000,7 @@ export type UpdateCoreViewMutationVariables = Exact<{
}>;
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
export type UpdateCoreViewFieldMutationVariables = Exact<{
input: UpdateViewFieldInput;
@@ -5028,7 +5029,7 @@ export type UpdateCoreViewGroupMutationVariables = Exact<{
}>;
export type UpdateCoreViewGroupMutation = { __typename?: 'Mutation', updateCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type UpdateCoreViewGroupMutation = { __typename?: 'Mutation', updateCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } };
export type UpdateCoreViewSortMutationVariables = Exact<{
id: Scalars['String'];
@@ -5041,7 +5042,7 @@ export type UpdateCoreViewSortMutation = { __typename?: 'Mutation', updateCoreVi
export type FindAllCoreViewsQueryVariables = Exact<{ [key: string]: never; }>;
export type FindAllCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
export type FindAllCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
export type FindManyCoreViewFieldsQueryVariables = Exact<{
viewId: Scalars['String'];
@@ -5069,7 +5070,7 @@ export type FindManyCoreViewGroupsQueryVariables = Exact<{
}>;
export type FindManyCoreViewGroupsQuery = { __typename?: 'Query', getCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type FindManyCoreViewGroupsQuery = { __typename?: 'Query', getCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
export type FindManyCoreViewSortsQueryVariables = Exact<{
viewId?: InputMaybe<Scalars['String']>;
@@ -5083,14 +5084,14 @@ export type FindManyCoreViewsQueryVariables = Exact<{
}>;
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
export type FindOneCoreViewQueryVariables = Exact<{
id: Scalars['String'];
}>;
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } | null };
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } | null };
export type FindOneCoreViewFieldQueryVariables = Exact<{
id: Scalars['String'];
@@ -5118,7 +5119,7 @@ export type FindOneCoreViewGroupQueryVariables = Exact<{
}>;
export type FindOneCoreViewGroupQuery = { __typename?: 'Query', getCoreViewGroup?: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } | null };
export type FindOneCoreViewGroupQuery = { __typename?: 'Query', getCoreViewGroup?: { __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null } | null };
export type FindOneCoreViewSortQueryVariables = Exact<{
id: Scalars['String'];
@@ -5299,7 +5300,6 @@ export const ViewSortFragmentFragmentDoc = gql`
export const ViewGroupFragmentFragmentDoc = gql`
fragment ViewGroupFragment on CoreViewGroup {
id
fieldMetadataId
isVisible
fieldValue
position
@@ -5322,6 +5322,7 @@ export const ViewFragmentFragmentDoc = gql`
openRecordIn
kanbanAggregateOperation
kanbanAggregateOperationFieldMetadataId
mainGroupByFieldMetadataId
anyFieldFilterValue
calendarFieldMetadataId
calendarLayout
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Bladsy"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "الصفحة"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Pàgina"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Stránka"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Side"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Seite"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Σελίδα"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
+10
View File
@@ -7066,6 +7066,16 @@ msgstr "p"
msgid "Page"
msgstr "Page"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr "page layout tab"
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr "page layout widget"
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr "p"
msgid "Page"
msgstr "Página"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Sivu"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Page"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
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
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "דף"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Oldal"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Pagina"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "ページ"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "페이지"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Pagina"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Side"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Strona"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7066,6 +7066,16 @@ msgstr ""
msgid "Page"
msgstr ""
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Página"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Página"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Pagină"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
Binary file not shown.
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Страница"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7073,6 +7073,16 @@ msgstr ""
msgid "Page"
msgstr "Sida"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Sayfa"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Сторінка"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "Trang"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "页面"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -7071,6 +7071,16 @@ msgstr ""
msgid "Page"
msgstr "頁"
#. js-lingui-id: HFlGEK
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout tab"
msgstr ""
#. js-lingui-id: sVcqjZ
#: src/modules/metadata-error-handler/hooks/useMetadataErrorHandler.ts
msgid "page layout widget"
msgstr ""
#. js-lingui-id: boJlGf
#: src/pages/not-found/NotFound.tsx
msgid "Page Not Found"
@@ -3,6 +3,7 @@ import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode';
import { useRecoilValue } from 'recoil';
import { useResetLocationHash } from 'twenty-ui/utilities';
export const EditDashboardSingleRecordAction = () => {
const recordId = useSelectedRecordIdOrThrow();
@@ -14,8 +15,11 @@ export const EditDashboardSingleRecordAction = () => {
const { setIsPageLayoutInEditMode } =
useSetIsPageLayoutInEditMode(pageLayoutId);
const { resetLocationHash } = useResetLocationHash();
const handleClick = () => {
setIsPageLayoutInEditMode(true);
resetLocationHash();
};
return <Action onClick={handleClick} />;
@@ -15,8 +15,8 @@ export type Company = {
};
address: {
__typename?: 'Address';
addressLine1: string;
addressLine2: string;
addressStreet1: string;
addressStreet2: string;
addressCity: string;
addressState: string;
addressPostcode: string;
@@ -26,6 +26,8 @@ export const useMetadataErrorHandler = () => {
role: t`role`,
roleTarget: t`role target`,
agent: t`agent`,
pageLayoutWidget: t`page layout widget`,
pageLayoutTab: t`page layout tab`,
} as const satisfies Record<AllMetadataName, string>;
const handleMetadataError = useCallback(
@@ -1,75 +1,35 @@
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { isSwitchingToKanbanViewTypeComponentState } from '@/object-record/record-board/states/isSwitchingToKanbanViewTypeComponentState';
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroup';
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView';
import { coreViewsState } from '@/views/states/coreViewState';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { type ViewGroup } from '@/views/types/ViewGroup';
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { convertViewTypeToCore } from '@/views/utils/convertViewTypeToCore';
import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar';
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
import { useCallback } from 'react';
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { assertUnreachable, isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { ViewCalendarLayout } from '~/generated/graphql';
export const useSetViewTypeFromLayoutOptionsMenu = () => {
const { updateCurrentView } = useUpdateCurrentView();
const setRecordIndexViewType = useSetRecoilState(recordIndexViewTypeState);
const isSwitchingToKanbanViewTypeCallbackState =
useRecoilComponentCallbackState(isSwitchingToKanbanViewTypeComponentState);
const { availableFieldsForKanban } = useGetAvailableFieldsForKanban();
const { objectMetadataItem } = useRecordIndexContextOrThrow();
const { loadRecordIndexStates } = useLoadRecordIndexStates();
const { createViewGroups } = usePersistViewGroupRecords();
const { availableFieldsForCalendar } = useGetAvailableFieldsForCalendar();
const createViewGroupAssociatedWithKanbanField = useCallback(
async (randomFieldForKanban: string, currentViewId: string) => {
const viewGroupsToCreate =
objectMetadataItem.fields
?.find((field) => field.id === randomFieldForKanban)
?.options?.map(
(option, index) =>
({
id: v4(),
__typename: 'ViewGroup',
fieldMetadataId: randomFieldForKanban,
fieldValue: option.value,
isVisible: true,
position: index,
}) satisfies ViewGroup,
) ?? [];
viewGroupsToCreate.push({
__typename: 'ViewGroup',
id: v4(),
fieldValue: '',
position: viewGroupsToCreate.length,
isVisible: true,
fieldMetadataId: randomFieldForKanban,
} satisfies ViewGroup);
await createViewGroups({
inputs: viewGroupsToCreate.map(({ __typename, ...viewGroup }) => ({
...viewGroup,
viewId: currentViewId,
})),
});
return viewGroupsToCreate;
},
[objectMetadataItem, createViewGroups],
);
const setAndPersistViewType = useRecoilCallback(
({ snapshot, set }) =>
async (viewType: ViewType) => {
@@ -104,20 +64,20 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
switch (viewType) {
case ViewType.Kanban: {
set(isSwitchingToKanbanViewTypeCallbackState, true);
if (availableFieldsForKanban.length === 0) {
throw new Error('No fields for kanban - should not happen');
}
if (currentView.viewGroups.length === 0) {
const viewGroups = await createViewGroupAssociatedWithKanbanField(
availableFieldsForKanban[0].id,
currentView.id,
);
loadRecordIndexStates(
{ ...currentView, viewGroups },
objectMetadataItem,
);
const mainGroupByFieldMetadataId = availableFieldsForKanban[0].id;
updateCurrentViewParams.mainGroupByFieldMetadataId =
mainGroupByFieldMetadataId;
if (shouldChangeIcon(currentView.icon, currentView.type)) {
updateCurrentViewParams.icon =
viewTypeIconMapping(viewType).displayName;
}
setRecordIndexViewType(viewType);
set(coreViewsState, [
...existingCoreViews.filter(
@@ -126,16 +86,19 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
{
...currentCoreView,
type: convertViewTypeToCore(viewType),
mainGroupByFieldMetadataId,
},
]);
if (shouldChangeIcon(currentView.icon, currentView.type)) {
updateCurrentViewParams.icon =
viewTypeIconMapping(viewType).displayName;
}
return await updateCurrentView(updateCurrentViewParams);
await updateCurrentView(updateCurrentViewParams);
return;
}
case ViewType.Table: {
if (shouldChangeIcon(currentView.icon, currentView.type)) {
updateCurrentViewParams.icon =
viewTypeIconMapping(viewType).displayName;
}
updateCurrentViewParams.mainGroupByFieldMetadataId = null;
await updateCurrentView(updateCurrentViewParams);
setRecordIndexViewType(viewType);
set(coreViewsState, [
...existingCoreViews.filter(
@@ -143,15 +106,11 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
),
{
...currentCoreView,
mainGroupByFieldMetadataId: null,
type: convertViewTypeToCore(viewType),
},
]);
if (shouldChangeIcon(currentView.icon, currentView.type)) {
updateCurrentViewParams.icon =
viewTypeIconMapping(viewType).displayName;
}
return await updateCurrentView(updateCurrentViewParams);
return;
}
case ViewType.Calendar: {
if (availableFieldsForCalendar.length === 0) {
@@ -167,6 +126,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
),
{
...currentCoreView,
mainGroupByFieldMetadataId: null,
type: convertViewTypeToCore(viewType),
calendarLayout: ViewCalendarLayout.MONTH,
calendarFieldMetadataId,
@@ -190,6 +150,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
updateCurrentViewParams.calendarLayout = ViewCalendarLayout.MONTH;
updateCurrentViewParams.calendarFieldMetadataId =
calendarFieldMetadataId;
updateCurrentViewParams.mainGroupByFieldMetadataId = null;
return await updateCurrentView(updateCurrentViewParams);
}
default: {
@@ -198,13 +159,13 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
}
},
[
isSwitchingToKanbanViewTypeCallbackState,
availableFieldsForKanban,
objectMetadataItem,
updateCurrentView,
setRecordIndexViewType,
createViewGroupAssociatedWithKanbanField,
loadRecordIndexStates,
updateCurrentView,
availableFieldsForCalendar,
loadRecordIndexStates,
objectMetadataItem,
],
);
@@ -1,5 +1,6 @@
import { useTriggerRecordBoardFetchMore } from '@/object-record/record-board/hooks/useTriggerRecordBoardFetchMore';
import { useTriggerRecordBoardInitialQuery } from '@/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery';
import { isSwitchingToKanbanViewTypeComponentState } from '@/object-record/record-board/states/isSwitchingToKanbanViewTypeComponentState';
import { lastRecordBoardQueryIdentifierComponentState } from '@/object-record/record-board/states/lastRecordBoardQueryIdentifierComponentState';
import { recordBoardCurrentGroupByQueryOffsetComponentState } from '@/object-record/record-board/states/recordBoardCurrentGroupByQueryOffsetComponentState';
import { recordBoardIsFetchingMoreComponentState } from '@/object-record/record-board/states/recordBoardIsFetchingMoreComponentState';
@@ -22,6 +23,11 @@ export const RecordBoardQueryEffect = () => {
const [lastRecordBoardQueryIdentifier, setLastRecordBoardQueryIdentifier] =
useRecoilComponentState(lastRecordBoardQueryIdentifierComponentState);
const [
isSwitchingToKanbanViewTypeCallbackState,
setIsSwitchingToKanbanViewTypeComponentState,
] = useRecoilComponentState(isSwitchingToKanbanViewTypeComponentState);
const [recordIndexRecordGroupsAreInInitialLoading] = useRecoilComponentState(
recordIndexRecordGroupsAreInInitialLoadingComponentState,
);
@@ -60,9 +66,10 @@ export const RecordBoardQueryEffect = () => {
useEffect(() => {
if (
!recordIndexRecordGroupsAreInInitialLoading &&
queryIdentifierHasChanged
(queryIdentifierHasChanged || isSwitchingToKanbanViewTypeCallbackState)
) {
triggerRecordBoardInitialQuery();
setIsSwitchingToKanbanViewTypeComponentState(false);
} else if (
!recordIndexRecordGroupsAreInInitialLoading &&
shouldFetchMore &&
@@ -82,6 +89,8 @@ export const RecordBoardQueryEffect = () => {
shouldFetchMore,
recordBoardIsFetchingMore,
triggerRecordBoardFetchMore,
isSwitchingToKanbanViewTypeCallbackState,
setIsSwitchingToKanbanViewTypeComponentState,
]);
return null;
@@ -0,0 +1,9 @@
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const isSwitchingToKanbanViewTypeComponentState =
createComponentState<boolean>({
key: 'isSwitchingToKanbanViewTypeComponentState',
componentInstanceContext: ContextStoreComponentInstanceContext,
defaultValue: false,
});
@@ -8,12 +8,14 @@ import { originalDragSelectionComponentState } from '@/object-record/record-drag
import { processGroupDrop } from '@/object-record/record-drag/utils/processGroupDrop';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { RECORD_INDEX_REMOVE_SORTING_MODAL_ID } from '@/object-record/record-index/constants/RecordIndexRemoveSortingModalId';
import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState';
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
export const useProcessTableWithGroupRecordDrop = () => {
@@ -47,6 +49,10 @@ export const useProcessTableWithGroupRecordDrop = () => {
originalDragSelectionComponentState,
);
const groupFieldMetadata = useRecoilComponentValue(
recordIndexGroupFieldMetadataItemComponentState,
);
const processTableWithGroupRecordDrop = useRecoilCallback(
({ snapshot }) =>
(result: DropResult) => {
@@ -63,7 +69,7 @@ export const useProcessTableWithGroupRecordDrop = () => {
}
const fieldMetadata = objectMetadataItem.fields.find(
(field) => field.id === destinationRecordGroup.fieldMetadataId,
(field) => field.id === groupFieldMetadata?.id,
);
if (!isDefined(fieldMetadata)) {
@@ -110,14 +116,15 @@ export const useProcessTableWithGroupRecordDrop = () => {
});
},
[
currentRecordSortsCallbackState,
objectMetadataItem.fields,
recordIdsByGroupFamilyState,
updateOneRow,
openModal,
selectedRowIdsSelector,
originalDragSelectionCallbackState,
isDraggingRecordCallbackState,
selectedRowIdsSelector,
currentRecordSortsCallbackState,
recordIdsByGroupFamilyState,
groupFieldMetadata?.id,
openModal,
updateOneRow,
],
);
@@ -1,21 +1,25 @@
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition';
import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useMemo } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const useRecordGroupFilter = (fields: FieldMetadataItem[]) => {
const currentRecordGroupDefinition = useCurrentRecordGroupDefinition();
const groupFieldMetadata = useRecoilComponentValue(
recordIndexGroupFieldMetadataItemComponentState,
);
const recordGroupFilter = useMemo(() => {
if (isDefined(currentRecordGroupDefinition)) {
const fieldMetadataItem = fields.find(
(fieldMetadataItem) =>
fieldMetadataItem.id === currentRecordGroupDefinition.fieldMetadataId,
(fieldMetadataItem) => fieldMetadataItem.id === groupFieldMetadata?.id,
);
if (!fieldMetadataItem) {
throw new Error(
`Field metadata item with id ${currentRecordGroupDefinition.fieldMetadataId} not found`,
`Field metadata item with id ${groupFieldMetadata?.id} not found`,
);
}
@@ -31,7 +35,7 @@ export const useRecordGroupFilter = (fields: FieldMetadataItem[]) => {
}
return {};
}, [currentRecordGroupDefinition, fields]);
}, [currentRecordGroupDefinition, fields, groupFieldMetadata?.id]);
return { recordGroupFilter };
};
@@ -3,7 +3,9 @@ import { useSetRecordGroups } from '@/object-record/record-group/hooks/useSetRec
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector';
import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState';
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useSaveCurrentViewGroups } from '@/views/hooks/useSaveCurrentViewGroups';
import { type ViewType } from '@/views/types/ViewType';
@@ -37,6 +39,10 @@ export const useReorderRecordGroups = ({
const { saveViewGroups } = useSaveCurrentViewGroups();
const groupFieldMetadata = useRecoilComponentValue(
recordIndexGroupFieldMetadataItemComponentState,
);
const reorderRecordGroups = useRecoilCallback(
({ snapshot }) =>
({ fromIndex, toIndex }: ReorderRecordGroupsParams) => {
@@ -80,17 +86,23 @@ export const useReorderRecordGroups = ({
];
}, []);
setRecordGroups(
updatedRecordGroups,
if (!isDefined(groupFieldMetadata?.id)) {
throw new Error('mainGroupByFieldMetadataId is required');
}
setRecordGroups({
mainGroupByFieldMetadataId: groupFieldMetadata?.id,
recordGroups: updatedRecordGroups,
recordIndexId,
objectMetadataItem.id,
);
objectMetadataItemId: objectMetadataItem.id,
});
saveViewGroups(
mapRecordGroupDefinitionsToViewGroups(updatedRecordGroups),
);
},
[
objectMetadataItem.id,
groupFieldMetadata?.id,
recordIndexId,
saveViewGroups,
setRecordGroups,
@@ -16,11 +16,17 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
export const useSetRecordGroups = () => {
const setRecordGroups = useRecoilCallback(
({ snapshot, set }) =>
(
recordGroups: RecordGroupDefinition[],
recordIndexId: string,
objectMetadataItemId: string,
) => {
({
mainGroupByFieldMetadataId,
recordGroups,
recordIndexId,
objectMetadataItemId,
}: {
mainGroupByFieldMetadataId: string;
recordGroups: RecordGroupDefinition[];
recordIndexId: string;
objectMetadataItemId: string;
}) => {
const objectMetadataItems = snapshot
.getLoadable(objectMetadataItemsState)
.getValue();
@@ -40,7 +46,8 @@ export const useSetRecordGroups = () => {
instanceId: recordIndexId,
}),
);
const fieldMetadataId = recordGroups?.[0]?.fieldMetadataId;
const fieldMetadataId = mainGroupByFieldMetadataId;
const fieldMetadata = fieldMetadataId
? objectMetadataItem.fields.find(
(field) => field.id === fieldMetadataId,
@@ -105,26 +112,34 @@ export const useSetRecordGroups = () => {
);
const setRecordGroupsFromViewGroups = useCallback(
(
viewId: string,
viewGroups: ViewGroup[],
objectMetadataItem: ObjectMetadataItem,
) => {
({
viewId,
mainGroupByFieldMetadataId,
viewGroups,
objectMetadataItem,
}: {
viewId: string;
mainGroupByFieldMetadataId: string;
viewGroups: ViewGroup[];
objectMetadataItem: ObjectMetadataItem;
}) => {
const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId(
objectMetadataItem.namePlural,
viewId,
);
const newGroupDefinitions = mapViewGroupsToRecordGroupDefinitions({
mainGroupByFieldMetadataId,
objectMetadataItem,
viewGroups,
});
setRecordGroups(
newGroupDefinitions,
setRecordGroups({
mainGroupByFieldMetadataId,
recordGroups: newGroupDefinitions,
recordIndexId,
objectMetadataItem.id,
);
objectMetadataItemId: objectMetadataItem.id,
});
},
[setRecordGroups],
);
@@ -6,7 +6,6 @@ export const enum RecordGroupDefinitionType {
export type RecordGroupDefinition = {
id: string;
fieldMetadataId: string;
type: RecordGroupDefinitionType;
title: string;
value: string | null;
@@ -2,18 +2,20 @@ import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { useSetRecordGroups } from '@/object-record/record-group/hooks/useSetRecordGroups';
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { usePersistView } from '@/views/hooks/internal/usePersistView';
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroup';
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
import { type ViewGroup } from '@/views/types/ViewGroup';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { type CoreView } from '~/generated/graphql';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
export const useHandleRecordGroupField = () => {
const { createViewGroups, deleteViewGroups } = usePersistViewGroupRecords();
const currentViewIdCallbackState = useRecoilComponentCallbackState(
contextStoreCurrentViewIdComponentState,
);
@@ -25,6 +27,9 @@ export const useHandleRecordGroupField = () => {
const { setRecordGroupsFromViewGroups } = useSetRecordGroups();
const { updateView } = usePersistView();
const { loadRecordIndexStates } = useLoadRecordIndexStates();
const { refreshCoreViewsByObjectMetadataId } =
useRefreshCoreViewsByObjectMetadataId();
const handleRecordGroupFieldChange = useRecoilCallback(
({ snapshot }) =>
@@ -50,16 +55,29 @@ export const useHandleRecordGroupField = () => {
return;
}
await updateView({
const updatedViewResult = await updateView({
id: view.id,
input: {
mainGroupByFieldMetadataId: fieldMetadataItem.id,
},
});
if (updatedViewResult.status === 'successful') {
const updatedCoreView = updatedViewResult.response.data
?.updateCoreView as CoreView;
if (isDefined(updatedCoreView)) {
const updatedViewConverted = convertCoreViewToView(updatedCoreView);
await loadRecordIndexStates(
updatedViewConverted,
objectMetadataItem,
);
}
}
const existingGroupKeys = new Set(
view.viewGroups.map(
(group) => `${group.fieldMetadataId}:${group.fieldValue}`,
(group) => `${view.mainGroupByFieldMetadataId}:${group.fieldValue}`,
),
);
@@ -79,7 +97,6 @@ export const useHandleRecordGroupField = () => {
fieldValue: option.value,
isVisible: true,
position: index,
fieldMetadataId: fieldMetadataItem.id,
}) satisfies ViewGroup,
);
@@ -93,45 +110,25 @@ export const useHandleRecordGroupField = () => {
fieldValue: '',
isVisible: true,
position: fieldMetadataItem.options.length,
fieldMetadataId: fieldMetadataItem.id,
} satisfies ViewGroup);
}
const viewGroupsToDelete = view.viewGroups.filter(
(group) => group.fieldMetadataId !== fieldMetadataItem.id,
);
const newViewGroupsList = [
...view.viewGroups.filter(
(group) => group.fieldMetadataId === fieldMetadataItem.id,
(_group) =>
view.mainGroupByFieldMetadataId === fieldMetadataItem.id,
),
...viewGroupsToCreate,
];
setRecordGroupsFromViewGroups(
view.id,
newViewGroupsList,
setRecordGroupsFromViewGroups({
viewId: view.id,
mainGroupByFieldMetadataId: fieldMetadataItem.id,
viewGroups: newViewGroupsList,
objectMetadataItem,
);
});
if (viewGroupsToCreate.length > 0) {
await createViewGroups({
inputs: viewGroupsToCreate.map(({ __typename, ...viewGroup }) => ({
...viewGroup,
viewId: view.id,
})),
});
}
if (viewGroupsToDelete.length > 0) {
await deleteViewGroups(
viewGroupsToDelete.map((group) => ({
input: {
id: group.id,
},
})),
);
}
await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id);
},
[
currentViewIdCallbackState,
@@ -139,8 +136,8 @@ export const useHandleRecordGroupField = () => {
updateView,
setRecordGroupsFromViewGroups,
objectMetadataItem,
createViewGroups,
deleteViewGroups,
refreshCoreViewsByObjectMetadataId,
loadRecordIndexStates,
],
);
@@ -165,23 +162,14 @@ export const useHandleRecordGroupField = () => {
return;
}
await deleteViewGroups(
view.viewGroups.map((group) => ({
input: {
id: group.id,
},
})),
);
setRecordGroupsFromViewGroups(view.id, [], objectMetadataItem);
await updateView({
id: view.id,
input: {
mainGroupByFieldMetadataId: null,
},
});
},
[
deleteViewGroups,
currentViewIdCallbackState,
getViewFromPrefetchState,
setRecordGroupsFromViewGroups,
objectMetadataItem,
],
[currentViewIdCallbackState, getViewFromPrefetchState, updateView],
);
return { handleRecordGroupFieldChange, resetRecordGroupField };
@@ -178,11 +178,12 @@ export const useLoadRecordIndexStates = () => {
onViewFieldsChange(view.viewFields, objectMetadataItem);
setRecordGroupsFromViewGroups(
view.id,
view.viewGroups,
setRecordGroupsFromViewGroups({
viewId: view.id,
mainGroupByFieldMetadataId: view.mainGroupByFieldMetadataId ?? '',
viewGroups: view.viewGroups,
objectMetadataItem,
);
});
setContextStoreTargetedRecordsRuleComponentState((prev) => ({
...prev,
@@ -199,9 +200,9 @@ export const useLoadRecordIndexStates = () => {
view.calendarFieldMetadataId ?? null,
);
if (isDefined(view.viewGroups?.[0]?.fieldMetadataId)) {
if (isDefined(view.mainGroupByFieldMetadataId)) {
const recordIndexGroupFieldMetadataItemId =
view.viewGroups?.[0]?.fieldMetadataId;
view.mainGroupByFieldMetadataId;
const { fieldMetadataItem: recordIndexGroupFieldMetadataItem } =
getFieldMetadataItemByIdOrThrow(
@@ -1,9 +1,11 @@
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord';
import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil';
import { IconPlus } from 'twenty-ui/display';
@@ -17,12 +19,16 @@ export const RecordTableRecordGroupSectionAddNew = () => {
recordGroupDefinitionFamilyState(currentRecordGroupId),
);
const mainGroupByFieldMetadata = useRecoilComponentValue(
recordIndexGroupFieldMetadataItemComponentState,
);
const { createNewIndexRecord } = useCreateNewIndexRecord({
objectMetadataItem,
});
const fieldMetadataItem = objectMetadataItem.fields.find(
(field) => field.id === recordGroup?.fieldMetadataId,
(field) => field.id === mainGroupByFieldMetadata?.id,
);
const objectPermissions = useObjectPermissionsForObject(
@@ -6,23 +6,10 @@ import { usePageLayoutContentContext } from '@/page-layout/contexts/PageLayoutCo
import { usePageLayoutTabWithVisibleWidgetsOrThrow } from '@/page-layout/hooks/usePageLayoutTabWithVisibleWidgetsOrThrow';
import { useReorderPageLayoutWidgets } from '@/page-layout/hooks/useReorderPageLayoutWidgets';
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { FeatureFlagKey } from '~/generated/graphql';
const StyledContainer = styled.div<{ isInPinnedTab: boolean }>`
background: ${({ theme }) => theme.background.primary};
box-sizing: border-box;
flex: 1;
min-height: 100%;
position: relative;
width: 100%;
padding: ${({ theme, isInPinnedTab }) =>
isInPinnedTab ? 0 : theme.spacing(2)};
`;
export const PageLayoutContent = () => {
const isRecordPageEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
@@ -39,7 +26,6 @@ export const PageLayoutContent = () => {
const activeTab = usePageLayoutTabWithVisibleWidgetsOrThrow(tabId);
const { layoutMode } = usePageLayoutContentContext();
const { isInPinnedTab } = useIsInPinnedTab();
const isCanvasLayout = isRecordPageEnabled && layoutMode === 'canvas';
const isVerticalList = isRecordPageEnabled && layoutMode === 'vertical-list';
@@ -49,17 +35,13 @@ export const PageLayoutContent = () => {
}
if (isVerticalList) {
return (
<StyledContainer isInPinnedTab={isInPinnedTab}>
{isPageLayoutInEditMode ? (
<PageLayoutVerticalListEditor
widgets={activeTab.widgets}
onReorder={reorderWidgets}
/>
) : (
<PageLayoutVerticalListViewer widgets={activeTab.widgets} />
)}
</StyledContainer>
return isPageLayoutInEditMode ? (
<PageLayoutVerticalListEditor
widgets={activeTab.widgets}
onReorder={reorderWidgets}
/>
) : (
<PageLayoutVerticalListViewer widgets={activeTab.widgets} />
);
}
@@ -36,7 +36,6 @@ import {
import { isDefined } from 'twenty-shared/utils';
const StyledGridContainer = styled.div`
background: ${({ theme }) => theme.background.primary};
box-sizing: border-box;
flex: 1;
min-height: 100%;
@@ -139,65 +138,61 @@ export const PageLayoutGridLayout = ({ tabId }: PageLayoutGridLayoutProps) => {
);
return (
<>
<StyledGridContainer ref={gridContainerRef}>
{isPageLayoutInEditMode && (
<>
<PageLayoutGridOverlay />
<PageLayoutGridLayoutDragSelector
gridContainerRef={gridContainerRef}
/>
</>
)}
<StyledGridContainer ref={gridContainerRef}>
{isPageLayoutInEditMode && (
<>
<PageLayoutGridOverlay />
<PageLayoutGridLayoutDragSelector
gridContainerRef={gridContainerRef}
/>
</>
)}
<ResponsiveGridLayout
className="layout"
layouts={layouts}
breakpoints={PAGE_LAYOUT_CONFIG.breakpoints}
cols={PAGE_LAYOUT_CONFIG.columns}
rowHeight={PAGE_LAYOUT_GRID_ROW_HEIGHT}
maxCols={12}
containerPadding={[0, 0]}
margin={[PAGE_LAYOUT_GRID_MARGIN, PAGE_LAYOUT_GRID_MARGIN]}
isDraggable={isPageLayoutInEditMode}
isResizable={isPageLayoutInEditMode}
draggableHandle=".drag-handle"
compactType="vertical"
preventCollision={false}
resizeHandle={
isPageLayoutInEditMode ? <PageLayoutGridResizeHandle /> : undefined
}
resizeHandles={['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw']}
onDragStart={(_layout, _oldItem, newItem) => {
setDraggingWidgetId(newItem.i);
}}
onDragStop={() => {
setDraggingWidgetId(null);
}}
onResizeStart={(_layout, _oldItem, newItem) => {
setResizingWidgetId(newItem.i);
}}
onResizeStop={() => {
setResizingWidgetId(null);
}}
onLayoutChange={handleLayoutChangeWithoutPendingPlaceholder}
onBreakpointChange={(newBreakpoint) =>
setPageLayoutCurrentBreakpoint(
newBreakpoint as PageLayoutBreakpoint,
)
}
>
{gridLayoutItems.map((item) => (
<ReactGridLayoutCardWrapper key={item.id}>
{item.type === 'placeholder' ? (
<WidgetPlaceholder />
) : (
<WidgetRenderer widget={item.widget} />
)}
</ReactGridLayoutCardWrapper>
))}
</ResponsiveGridLayout>
</StyledGridContainer>
</>
<ResponsiveGridLayout
className="layout"
layouts={layouts}
breakpoints={PAGE_LAYOUT_CONFIG.breakpoints}
cols={PAGE_LAYOUT_CONFIG.columns}
rowHeight={PAGE_LAYOUT_GRID_ROW_HEIGHT}
maxCols={12}
containerPadding={[0, 0]}
margin={[PAGE_LAYOUT_GRID_MARGIN, PAGE_LAYOUT_GRID_MARGIN]}
isDraggable={isPageLayoutInEditMode}
isResizable={isPageLayoutInEditMode}
draggableHandle=".drag-handle"
compactType="vertical"
preventCollision={false}
resizeHandle={
isPageLayoutInEditMode ? <PageLayoutGridResizeHandle /> : undefined
}
resizeHandles={['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw']}
onDragStart={(_layout, _oldItem, newItem) => {
setDraggingWidgetId(newItem.i);
}}
onDragStop={() => {
setDraggingWidgetId(null);
}}
onResizeStart={(_layout, _oldItem, newItem) => {
setResizingWidgetId(newItem.i);
}}
onResizeStop={() => {
setResizingWidgetId(null);
}}
onLayoutChange={handleLayoutChangeWithoutPendingPlaceholder}
onBreakpointChange={(newBreakpoint) =>
setPageLayoutCurrentBreakpoint(newBreakpoint as PageLayoutBreakpoint)
}
>
{gridLayoutItems.map((item) => (
<ReactGridLayoutCardWrapper key={item.id}>
{item.type === 'placeholder' ? (
<WidgetPlaceholder />
) : (
<WidgetRenderer widget={item.widget} />
)}
</ReactGridLayoutCardWrapper>
))}
</ResponsiveGridLayout>
</StyledGridContainer>
);
};
@@ -6,9 +6,21 @@ import { usePageLayoutTabWithVisibleWidgetsOrThrow } from '@/page-layout/hooks/u
import { getTabLayoutMode } from '@/page-layout/utils/getTabLayoutMode';
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import styled from '@emotion/styled';
import { PageLayoutType } from '~/generated/graphql';
const StyledContainer = styled.div`
background: ${({ theme }) => theme.background.secondary};
border-bottom-left-radius: 8px;
border-right: ${({ theme }) => `1px solid ${theme.border.color.medium}`};
border-top-left-radius: 8px;
box-sizing: border-box;
display: grid;
grid-template-rows: auto 1fr;
height: 100%;
`;
type PageLayoutLeftPanelProps = {
pinnedLeftTabId: string;
};
@@ -31,7 +43,7 @@ export const PageLayoutLeftPanel = ({
});
return (
<ShowPageLeftContainer>
<StyledContainer>
<SummaryCard
objectNameSingular={targetRecordIdentifier.targetObjectNameSingular}
objectRecordId={targetRecordIdentifier.id}
@@ -44,8 +56,14 @@ export const PageLayoutLeftPanel = ({
layoutMode,
}}
>
<PageLayoutContent />
<ScrollWrapper
componentInstanceId={`page-layout-left-panel-${pinnedLeftTabId}`}
defaultEnableXScroll={false}
defaultEnableYScroll={true}
>
<PageLayoutContent />
</ScrollWrapper>
</PageLayoutContentProvider>
</ShowPageLeftContainer>
</StyledContainer>
);
};
@@ -4,6 +4,7 @@ import { PageLayoutLeftPanel } from '@/page-layout/components/PageLayoutLeftPane
import { PageLayoutTabHeader } from '@/page-layout/components/PageLayoutTabHeader';
import { PageLayoutTabList } from '@/page-layout/components/PageLayoutTabList';
import { PageLayoutTabListEffect } from '@/page-layout/components/PageLayoutTabListEffect';
import { PAGE_LAYOUT_LEFT_PANEL_CONTAINER_WIDTH } from '@/page-layout/constants/PageLayoutLeftPanelContainerWidth';
import { useCreatePageLayoutTab } from '@/page-layout/hooks/useCreatePageLayoutTab';
import { useCurrentPageLayout } from '@/page-layout/hooks/useCurrentPageLayout';
import { useReorderPageLayoutTabs } from '@/page-layout/hooks/useReorderPageLayoutTabs';
@@ -16,31 +17,27 @@ import { getTabsByDisplayMode } from '@/page-layout/utils/getTabsByDisplayMode';
import { getTabsWithVisibleWidgets } from '@/page-layout/utils/getTabsWithVisibleWidgets';
import { sortTabsByPosition } from '@/page-layout/utils/sortTabsByPosition';
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { ShowPageContainer } from '@/ui/layout/page/components/ShowPageContainer';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
import { useIsMobile } from 'twenty-ui/utilities';
const StyledContainer = styled.div<{ hasPinnedTab: boolean }>`
display: grid;
grid-template-columns: ${({ hasPinnedTab }) =>
hasPinnedTab ? `${PAGE_LAYOUT_LEFT_PANEL_CONTAINER_WIDTH}px 1fr` : '1fr'};
grid-template-rows: minmax(0, 1fr);
height: 100%;
width: 100%;
`;
const StyledTabsAndDashboardContainer = styled.div`
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
overflow: hidden;
background: ${({ theme }) => theme.background.primary};
`;
const StyledShowPageRightContainer = styled.div`
display: flex;
flex-direction: column;
height: 100%;
justify-content: start;
width: 100%;
overflow: auto;
`;
const StyledPageLayoutTabList = styled(PageLayoutTabList)`
@@ -107,44 +104,43 @@ export const PageLayoutRendererContent = () => {
const sortedTabs = sortTabsByPosition(tabsToRenderInTabList);
return (
<ShowPageContainer>
<StyledContainer hasPinnedTab={isDefined(pinnedLeftTab)}>
{isDefined(pinnedLeftTab) && (
<PageLayoutLeftPanel pinnedLeftTabId={pinnedLeftTab.id} />
)}
<StyledShowPageRightContainer>
<StyledTabsAndDashboardContainer>
<PageLayoutTabListEffect
<StyledTabsAndDashboardContainer>
<PageLayoutTabListEffect
tabs={sortedTabs}
componentInstanceId={tabListInstanceId}
defaultTabIdToFocusOnMobileAndSidePanel={
currentPageLayout.defaultTabIdToFocusOnMobileAndSidePanel
}
/>
{(sortedTabs.length > 1 || isPageLayoutInEditMode) && (
<StyledPageLayoutTabList
tabs={sortedTabs}
behaveAsLinks={!isInRightDrawer && !isPageLayoutInEditMode}
componentInstanceId={tabListInstanceId}
defaultTabIdToFocusOnMobileAndSidePanel={
currentPageLayout.defaultTabIdToFocusOnMobileAndSidePanel
}
onAddTab={handleAddTab}
isReorderEnabled={isPageLayoutInEditMode}
onReorder={isPageLayoutInEditMode ? reorderTabs : undefined}
/>
{(sortedTabs.length > 1 || isPageLayoutInEditMode) && (
<StyledPageLayoutTabList
tabs={sortedTabs}
behaveAsLinks={false}
componentInstanceId={tabListInstanceId}
onAddTab={handleAddTab}
isReorderEnabled={isPageLayoutInEditMode}
onReorder={isPageLayoutInEditMode ? reorderTabs : undefined}
/>
)}
)}
<PageLayoutTabHeader />
<StyledScrollWrapper
componentInstanceId={getScrollWrapperInstanceIdFromPageLayoutId(
currentPageLayout.id,
)}
defaultEnableXScroll={false}
>
{isDefined(activeTabId) && (
<PageLayoutMainContent tabId={activeTabId} />
)}
</StyledScrollWrapper>
</StyledTabsAndDashboardContainer>
</StyledShowPageRightContainer>
</ShowPageContainer>
<PageLayoutTabHeader />
<StyledScrollWrapper
componentInstanceId={getScrollWrapperInstanceIdFromPageLayoutId(
currentPageLayout.id,
)}
defaultEnableXScroll={false}
>
{isDefined(activeTabId) && (
<PageLayoutMainContent tabId={activeTabId} />
)}
</StyledScrollWrapper>
</StyledTabsAndDashboardContainer>
</StyledContainer>
);
};
@@ -15,7 +15,6 @@ import { IconButton } from 'twenty-ui/input';
import { isPageLayoutTabDraggingComponentState } from '@/page-layout/states/isPageLayoutTabDraggingComponentState';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { TabListFromUrlOptionalEffect } from '@/ui/layout/tab-list/components/TabListFromUrlOptionalEffect';
import { TabListHiddenMeasurements } from '@/ui/layout/tab-list/components/TabListHiddenMeasurements';
import { TAB_LIST_GAP } from '@/ui/layout/tab-list/constants/TabListGap';
import { useTabListMeasurements } from '@/ui/layout/tab-list/hooks/useTabListMeasurements';
@@ -38,6 +37,7 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPag
import { pageLayoutTabListCurrentDragDroppableIdComponentState } from '@/page-layout/states/pageLayoutTabListCurrentDragDroppableIdComponentState';
import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState';
import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
import { TabListFromUrlOptionalEffect } from '@/ui/layout/tab-list/components/TabListFromUrlOptionalEffect';
import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
@@ -74,12 +74,13 @@ type PageLayoutTabListProps = Omit<TabListProps, 'tabs'> & {
isReorderEnabled: boolean;
onAddTab?: () => void;
onReorder?: (result: DropResult, provided: ResponderProvided) => boolean;
behaveAsLinks: boolean;
};
export const PageLayoutTabList = ({
tabs,
loading,
behaveAsLinks = true,
behaveAsLinks,
isInRightDrawer,
className,
componentInstanceId,
@@ -15,6 +15,7 @@ const StyledVerticalListContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(2)};
padding: ${({ theme }) => theme.spacing(2)};
`;
const StyledDraggableWrapper = styled.div<{ isDragging: boolean }>`
@@ -6,6 +6,7 @@ const StyledVerticalListContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(2)};
padding: ${({ theme }) => theme.spacing(2)};
`;
type PageLayoutVerticalListViewerProps = {
@@ -0,0 +1 @@
export const PAGE_LAYOUT_LEFT_PANEL_CONTAINER_WIDTH = 348;
@@ -5,73 +5,95 @@ import {
import { useGraphWidgetTooltipFloating } from '@/page-layout/widgets/graph/hooks/useGraphWidgetTooltipFloating';
import { useTheme } from '@emotion/react';
import { FloatingPortal, type VirtualElement } from '@floating-ui/react';
import { AnimatePresence, motion } from 'framer-motion';
import { animated, useSpring } from '@react-spring/web';
import { isDefined } from 'twenty-shared/utils';
type GraphWidgetFloatingTooltipProps = {
reference: Element | VirtualElement;
boundary: Element;
reference: Element | VirtualElement | null;
boundary: Element | null;
tooltipOffsetFromAnchorInPx: number;
items: GraphWidgetTooltipItem[];
indexLabel?: string;
highlightedKey?: string;
onGraphWidgetTooltipClick?: () => void;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
disablePointerEvents?: boolean;
};
export const GraphWidgetFloatingTooltip = ({
reference,
boundary,
tooltipOffsetFromAnchorInPx,
items,
indexLabel,
highlightedKey,
onGraphWidgetTooltipClick,
onMouseEnter,
onMouseLeave,
disablePointerEvents = false,
}: GraphWidgetFloatingTooltipProps) => {
const theme = useTheme();
const { refs, floatingStyles } = useGraphWidgetTooltipFloating(
const { refs, x, y, isPositioned } = useGraphWidgetTooltipFloating(
reference,
boundary,
tooltipOffsetFromAnchorInPx,
);
const xPos = x ?? 0;
const yPos = y ?? 0;
const shouldShow = isDefined(reference) && items.length > 0;
const isVisible = shouldShow && isPositioned;
const springStyles = useSpring({
from: {
transform: `translate(${xPos}px, ${yPos}px)`,
opacity: 0,
},
to: {
transform: `translate(${xPos}px, ${yPos}px)`,
opacity: isVisible ? 1 : 0,
},
config: {
tension: 300,
friction: 30,
},
immediate: !isPositioned || !shouldShow,
reset: !shouldShow,
});
if (!isDefined(boundary) || !(boundary instanceof HTMLElement)) {
return null;
}
return (
<FloatingPortal root={boundary}>
<div
<animated.div
ref={refs.setFloating}
style={{ ...floatingStyles, zIndex: theme.lastLayerZIndex }}
style={{
...springStyles,
position: 'fixed',
top: 0,
left: 0,
zIndex: theme.lastLayerZIndex,
pointerEvents: disablePointerEvents || !isVisible ? 'none' : 'auto',
}}
role="tooltip"
aria-live="polite"
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<AnimatePresence>
<motion.div
initial={{
opacity: 0,
scale: 0.95,
}}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{
duration: theme.animation.duration.fast,
ease: 'easeInOut',
}}
>
<GraphWidgetTooltip
items={items}
indexLabel={indexLabel}
highlightedKey={highlightedKey}
onGraphWidgetTooltipClick={onGraphWidgetTooltipClick}
/>
</motion.div>
</AnimatePresence>
</div>
{items.length > 0 && (
<GraphWidgetTooltip
items={items}
indexLabel={indexLabel}
highlightedKey={highlightedKey}
onGraphWidgetTooltipClick={onGraphWidgetTooltipClick}
/>
)}
</animated.div>
</FloatingPortal>
);
};
@@ -1,7 +1,9 @@
import { type Meta, type StoryObj } from '@storybook/react';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { GRAPH_WIDGET_TEST_INSTANCE_ID } from '@/page-layout/widgets/graph/__tests__/GraphWidgetTestWrapper';
import { GraphWidgetPieChart } from '@/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart';
import { GraphWidgetComponentInstanceContext } from '@/page-layout/widgets/graph/states/contexts/GraphWidgetComponentInstanceContext';
import { CatalogDecorator, ComponentDecorator } from 'twenty-ui/testing';
import {
AggregateOperations,
@@ -34,6 +36,13 @@ const meta: Meta<typeof GraphWidgetPieChart> = {
title: 'Modules/PageLayout/Widgets/GraphWidgetPieChart',
component: GraphWidgetPieChart,
decorators: [
(Story) => (
<GraphWidgetComponentInstanceContext.Provider
value={{ instanceId: GRAPH_WIDGET_TEST_INSTANCE_ID }}
>
<Story />
</GraphWidgetComponentInstanceContext.Provider>
),
ComponentDecorator,
I18nFrontDecorator,
ObjectMetadataItemsDecorator,
@@ -360,6 +369,13 @@ export const Storage: Story = {
export const Catalog: Story = {
decorators: [
(Story) => (
<GraphWidgetComponentInstanceContext.Provider
value={{ instanceId: GRAPH_WIDGET_TEST_INSTANCE_ID }}
>
<Story />
</GraphWidgetComponentInstanceContext.Provider>
),
CatalogDecorator,
I18nFrontDecorator,
ObjectMetadataItemsDecorator,
@@ -1 +0,0 @@
export const GRAPH_TOOLTIP_OFFSET_PX = 2;
@@ -1,15 +1,16 @@
import { GraphWidgetFloatingTooltip } from '@/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip';
import { BAR_CHART_TOOLTIP_OFFSET_PX } from '@/page-layout/widgets/graph/graphWidgetBarChart/constants/BarChartTooltipOffsetPx';
import { graphWidgetBarTooltipComponentState } from '@/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetBarTooltipComponentState';
import { type BarChartEnrichedKey } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartEnrichedKey';
import { getBarChartTooltipData } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/getBarChartTooltipData';
import { getTooltipReferenceFromBarChartElementAnchor } from '@/page-layout/widgets/graph/utils/getTooltipReferenceFromBarChartElementAnchor';
import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { type BarDatum, type ComputedDatum } from '@nivo/bar';
import { type RefObject } from 'react';
import { isDefined } from 'twenty-shared/utils';
type GraphBarChartTooltipProps = {
containerId: string;
containerRef: RefObject<HTMLDivElement>;
enrichedKeys: BarChartEnrichedKey[];
formatOptions: GraphValueFormatOptions;
enableGroupTooltip?: boolean;
@@ -20,7 +21,7 @@ type GraphBarChartTooltipProps = {
};
export const GraphBarChartTooltip = ({
containerId,
containerRef,
enrichedKeys,
formatOptions,
enableGroupTooltip = true,
@@ -33,6 +34,11 @@ export const GraphBarChartTooltip = ({
graphWidgetBarTooltipComponentState,
);
const containerElement = containerRef.current;
if (!isDefined(containerElement)) {
return null;
}
const handleTooltipClick: (() => void) | undefined = isDefined(onBarClick)
? () => {
if (isDefined(tooltipState)) {
@@ -51,38 +57,16 @@ export const GraphBarChartTooltip = ({
layout,
});
let reference = null;
let boundary = null;
if (isDefined(tooltipState)) {
try {
const positioning = getTooltipReferenceFromBarChartElementAnchor(
tooltipState.anchorElement,
containerId,
);
reference = positioning.reference;
boundary = positioning.boundary;
} catch {
reference = null;
boundary = null;
}
}
if (
!isDefined(tooltipData) ||
!isDefined(reference) ||
!isDefined(boundary)
) {
return null;
}
const reference = isDefined(tooltipState) ? tooltipState.anchorElement : null;
return (
<GraphWidgetFloatingTooltip
reference={reference}
boundary={boundary}
items={tooltipData.tooltipItems}
indexLabel={tooltipData.indexLabel}
highlightedKey={tooltipData.hoveredKey}
boundary={containerElement}
tooltipOffsetFromAnchorInPx={BAR_CHART_TOOLTIP_OFFSET_PX}
items={tooltipData?.tooltipItems ?? []}
indexLabel={tooltipData?.indexLabel}
highlightedKey={tooltipData?.hoveredKey}
onGraphWidgetTooltipClick={handleTooltipClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
@@ -284,7 +284,7 @@ export const GraphWidgetBarChart = ({
</GraphWidgetChartContainer>
<GraphBarChartTooltip
containerId={id}
containerRef={containerRef}
enrichedKeys={enrichedKeys}
formatOptions={formatOptions}
enableGroupTooltip={groupMode === 'stacked'}
@@ -0,0 +1 @@
export const BAR_CHART_TOOLTIP_OFFSET_PX = 2;
@@ -1,15 +1,17 @@
import { GraphWidgetFloatingTooltip } from '@/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip';
import { LINE_CHART_TOOLTIP_OFFSET_PX } from '@/page-layout/widgets/graph/graphWidgetLineChart/constants/LineChartTooltipOffsetPx';
import { graphWidgetLineTooltipComponentState } from '@/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineTooltipComponentState';
import { type LineChartEnrichedSeries } from '@/page-layout/widgets/graph/graphWidgetLineChart/types/LineChartEnrichedSeries';
import { getLineChartTooltipData } from '@/page-layout/widgets/graph/graphWidgetLineChart/utils/getLineChartTooltipData';
import { getTooltipReferenceFromLineChartPointAnchor } from '@/page-layout/widgets/graph/utils/getTooltipReferenceFromLineChartPointAnchor';
import { createVirtualElementFromContainerOffset } from '@/page-layout/widgets/graph/utils/createVirtualElementFromContainerOffset';
import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { type LineSeries, type Point } from '@nivo/line';
import { type RefObject } from 'react';
import { isDefined } from 'twenty-shared/utils';
type GraphLineChartTooltipProps = {
containerId: string;
containerRef: RefObject<HTMLDivElement>;
enrichedSeries: LineChartEnrichedSeries[];
formatOptions: GraphValueFormatOptions;
onSliceClick?: (point: Point<LineSeries>) => void;
@@ -18,7 +20,7 @@ type GraphLineChartTooltipProps = {
};
export const GraphLineChartTooltip = ({
containerId,
containerRef,
enrichedSeries,
formatOptions,
onSliceClick,
@@ -29,6 +31,11 @@ export const GraphLineChartTooltip = ({
graphWidgetLineTooltipComponentState,
);
const containerElement = containerRef.current;
if (!isDefined(containerElement)) {
return null;
}
const handleTooltipClick: (() => void) | undefined = isDefined(onSliceClick)
? () => {
if (!isDefined(tooltipState)) return;
@@ -52,38 +59,21 @@ export const GraphLineChartTooltip = ({
formatOptions,
});
let reference = null;
let boundary = null;
if (isDefined(tooltipState)) {
try {
const positioning = getTooltipReferenceFromLineChartPointAnchor(
containerId,
const reference = !isDefined(tooltipState)
? null
: createVirtualElementFromContainerOffset(
containerElement,
tooltipState.offsetLeft,
tooltipState.offsetTop,
);
reference = positioning.reference;
boundary = positioning.boundary;
} catch {
reference = null;
boundary = null;
}
}
if (
!isDefined(tooltipData) ||
!isDefined(reference) ||
!isDefined(boundary)
) {
return null;
}
return (
<GraphWidgetFloatingTooltip
reference={reference}
boundary={boundary}
items={tooltipData.items}
indexLabel={tooltipData.indexLabel}
boundary={containerElement}
tooltipOffsetFromAnchorInPx={LINE_CHART_TOOLTIP_OFFSET_PX}
items={tooltipData?.items ?? []}
indexLabel={tooltipData?.indexLabel}
highlightedKey={tooltipState?.highlightedSeriesId}
onGraphWidgetTooltipClick={handleTooltipClick}
onMouseEnter={onMouseEnter}
@@ -269,7 +269,7 @@ export const GraphWidgetLineChart = ({
/>
</GraphWidgetChartContainer>
<GraphLineChartTooltip
containerId={id}
containerRef={containerRef}
enrichedSeries={enrichedSeries}
formatOptions={formatOptions}
onSliceClick={onSliceClick}

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