Compare commits

..
Author SHA1 Message Date
Charles Bochet 5e29c0ef1d Fix remaining styled(Component) usages missed in initial pass
- WorkflowVariablesDropdown: styled(StyledDropdownButtonContainer) → parent wrapper
- DragSelect.stories: styled(ScrollWrapper) → parent container with overflow
- RecordTableActionRow: styled(RecordTableDragAndDropPlaceholderCell) → parent container
- RecordTableEmptyStateDisplay: styled(AnimatedPlaceholderEmptyContainer) → standalone styled.div
- TimelineCard: styled(AnimatedPlaceholderEmptyContainer) → conditional wrapper
- StyledMenuItemBase: merge StyledHoverableMenuItemBase into a standalone styled.div
  with all base + hoverable styles inlined (no styled(Component) extension)

Made-with: Cursor
2026-03-05 09:23:46 +01:00
Charles Bochet 09254580f2 Fix scroll regression in ScrollWrapper parent containers
Add overflow: hidden to parent containers wrapping ScrollWrapper.
Without it, flex items expand to content height instead of
constraining to available space, preventing scroll activation.

Made-with: Cursor
2026-03-05 09:19:03 +01:00
Charles Bochet ca8fccecff Remove all styled(Component) patterns in favor of parent wrappers and props
Replace 354 styled(Component) usages with:
- Parent styled containers for margin/layout CSS
- Child CSS selectors (> a, > div, > input) for third-party components (Link, TextareaAutosize, Handle, IMaskInput, DataGrid, QRCode)
- Existing component props (gridTemplateColumns, color, gap, align, etc.) for TableRow/TableCell
- Parent wrappers with > * selectors for intrinsic overrides on twenty-ui components

Made-with: Cursor
2026-03-05 09:09:43 +01:00
Charles Bochet bf2c6affbb Deprecate runtime theme objects in favor of CSS variables
- Remove ICON_SIZES/ICON_STROKES constants — all icon sizes/strokes
  now resolved at runtime via resolveThemeVariableAsNumber(themeCssVariables.icon.size/stroke.X)
- Move ColorSchemeContext/ColorSchemeProvider from twenty-ui/theme to
  twenty-ui/theme-constants — consumers no longer import from twenty-ui/theme
- Re-export ThemeColor, MAIN_COLOR_NAMES, getNextThemeColor, AnimationDuration
  from theme-constants via proxy files so the barrel generator picks them up
- Replace all ThemeContext/useContext(ThemeContext) usages across ~300 files
  with themeCssVariables (CSS contexts) or resolveThemeVariable (JS runtime)
- Simplify provider chain to just ColorSchemeProvider + DOM class toggle effect
- Fix pre-existing test failures: useIcons.test.ts (ES module spy),
  turnRecordFilterGroupIntoGqlOperationFilter.test.ts (Omit<RecordFilter,'id'>)
- Delete ThemeType, ThemeProvider, ThemeContextProvider

Made-with: Cursor
2026-03-05 02:03:24 +01:00
Abdullah.andGitHub 2493adbb87 fix: minimatch related dependabot alerts (#18396)
This PR fixes a good number of dependabot alerts associated to minimatch
transitive import.

There are a total of 28 alerts, merging this shall confirm which ones
remain open afterwards and make it easier to diagnose.
2026-03-04 23:47:02 +01:00
26f0a416a1 File storage cleaning (#18381)
- Remove feature flag
- Remove legacy methods in file-upload and file-service
- Migrate AI Chat to new file management

---------

Co-authored-by: Charles Bochet <[email protected]>
2026-03-04 23:46:03 +01:00
Charles BochetandGitHub c41a8e2b23 [DevXP] Simplify twenty-ui theme system: replace auto-generated files with static CSS variables (#18389)
## Summary

Now that Twenty has fully migrated from Emotion to Linaria, the theme
system has been simplified to remove unnecessary complexity that existed
only to support the old runtime injection pattern.

### What changed

- **Deleted** `generateThemeConstants.ts` script and the entire
`generated/` directory — no more auto-generation
- **Added** `theme-light.css` and `theme-dark.css`: static CSS files
with 991 custom properties each, scoped under `.light` and `.dark`
selectors respectively
- **Moved** `themeCssVariables.ts` out of `generated/` and hand-maintain
it as a static `as const` object of `var(--t-*)` references (Linaria can
statically evaluate these at build time)
- **Extracted** numeric constants (`MOBILE_VIEWPORT`, `ICON_SIZES`,
`ICON_STROKES`) into a new `constants.ts` — CSS variables can't be used
in media queries or as numeric icon size props
- **Simplified** `ThemeContextProvider`: removed
`ThemeCssVariableInjectorEffect` entirely; now uses a single
`useLayoutEffect` to toggle `.light`/`.dark` class on `<html>`
- **Added** `class="light"` to `index.html` as default to prevent FOUC
before React hydration

### Why

The previous setup maintained a dual system: JS theme objects
(`THEME_LIGHT`/`THEME_DARK`) used at runtime, plus a generation script
that produced CSS variable entry arrays, which were then injected into
the DOM by `ThemeCssVariableInjectorEffect`. With Linaria, theme values
only need to be CSS custom properties — the JS objects were redundant.
This PR removes ~250 lines of infrastructure while keeping the same
theming capabilities.
2026-03-04 23:30:25 +01:00
neo773GitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>Charles Bochetcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
4c001778c2 fix google signup edge case (#18365)
Fixes an edge case when a user signs up with Google and the profile
avatar network request times out, we crash instead of creating the user
without an avatar.

Added `axios-retry` to retry max 2 times and if it still fails we
gracefully skip avatar image instead of crashing

Fixes
Sentry TWENTY-SERVER-FDQ
Sonarly https://sonarly.com/issue/6564

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Charles Bochet <[email protected]>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-03-04 22:51:55 +01:00
Thomas TrompetteandGitHub 911a46aa45 Improve workflow perfs (#18376)
Workflow crons take a few minutes to run. Loading each repo takes ~200
to 300ms locally. Adding a lite mode so it takes less than 100ms.
Also doing batch promises.

Finally, cleaning runs timeout when there are too many. Doing batches as
well.
2026-03-04 18:29:12 +01:00
Paul RastoinandGitHub c53d281960 Fix invalid universal identifier format command cache flush (#18385)
# Introduction
Invalidating command impacted metadata and related metadata caches
entries
2026-03-04 17:43:01 +01:00
7f6b270a76 i18n - translations (#18388)
Created by Github action

---------

Co-authored-by: github-actions <[email protected]>
2026-03-04 17:32:14 +01:00
Abdul RahmanandGitHub c94657dc0a Navbar AI chats followup (#18336)
Addresses review comments from
[PR#18161](https://github.com/twentyhq/twenty/pull/18161)
2026-03-04 15:15:43 +00:00
aeedcf3353 Enable password reset from app.twenty.com with workspace fallback (#18271)
## Summary
- add a working `Forgot your password?` flow on `app.twenty.com` sign-in
- keep existing workspace-domain reset behavior
- when triggered without workspace context, resolve a workspace from the
user when possible, otherwise fallback to `app.twenty.com` reset URL

## Backend
- make `workspaceId` optional in `emailPasswordResetLink` input
- allow nullable `workspaceId` in password reset token DTO
- update reset token generation to accept optional `workspaceId`
- when missing, resolve first workspace by user membership
- if no workspace is found, persist token with `workspaceId = null`
- send reset links via:
  - workspace URL when `workspaceId` exists
  - app front URL + reset path when `workspaceId` is null

## Frontend
- make reset-link mutation `workspaceId` variable optional
- regenerate/patched generated metadata types accordingly
- add `Forgot your password?` in global password step
- allow reset request without workspace context in
`useHandleResetPassword`
- make reset page auto sign-in domain-aware (`workspace` vs `app`)
- apply design-system spacing above the global forgot-password link
(`theme.spacing(4)`)

## Tests
- extend reset-password service tests for:
  - explicit workspace id
  - inferred workspace when workspace id is missing
  - app-domain fallback when no workspace is found
- extend reset-password hook tests for with/without workspace context
- add focused global form test for forgot-password link rendering/click
behavior

## Product behavior for users with multiple workspaces
- no workspace chooser is shown in this flow
- backend uses the first resolvable workspace membership for the
reset-link domain
- password change remains account-level and works across all workspaces


Feature has been tested and is working 

<img width="3268" height="2106" alt="CleanShot 2026-02-26 at 14 09
14@2x"
src="https://github.com/user-attachments/assets/b5db3bed-f3aa-4d35-b54e-66e4d99141f9"
/>

---------

Co-authored-by: Etienne <[email protected]>
2026-03-04 15:14:38 +00:00
949 changed files with 16413 additions and 14427 deletions
@@ -1,7 +1,6 @@
import { defineLogicFunction, RoutePayload } from "twenty-sdk";
import { MetadataApiClient } from 'twenty-sdk/generated';
export const OAUTH_TOKEN_PAIRS_PATH = '/oauth/token-pairs';
type ApolloTokenResponse = {
@@ -53,16 +52,8 @@ const handler = async (event: RoutePayload): Promise<any> => {
const apolloClientSecret = process.env.APOLLO_CLIENT_SECRET ?? '';
const applicationId = process.env.APPLICATION_ID ?? '';
const metadataClient = new MetadataApiClient({});
const tokenPairs = await getAuthenticationTokenPairs(
code,
apolloClientId,
@@ -5,8 +5,6 @@ import {
} from 'twenty-sdk';
import { CoreApiClient } from 'twenty-sdk/generated';
type CompanyRecord = {
id: string;
name?: string;
@@ -38,8 +36,6 @@ type ApolloEnrichResponse = {
organization?: ApolloOrganization;
};
const extractDomain = (
domainName?: CompanyRecord['domainName'],
): string | undefined => {
@@ -172,7 +168,6 @@ const updateCompanyInTwenty = async (
}
};
type CompanyUpdateEvent = DatabaseEventPayload<
ObjectRecordUpdateEvent<CompanyRecord>
>;
@@ -181,7 +176,6 @@ const handler = async (
event: CompanyUpdateEvent,
): Promise<object | undefined> => {
const { recordId, properties } = event;
const { after: companyAfter } = properties;
@@ -206,7 +200,6 @@ const handler = async (
return { skipped: true, reason: 'no enrichment data to apply' };
}
await updateCompanyInTwenty(recordId, updateData);
const result = {
@@ -219,4 +219,3 @@ main().catch((error) => {
process.exit(1);
});
@@ -81,4 +81,3 @@ describe('HistoricalImporter', () => {
});
});
@@ -158,4 +158,3 @@ export class HistoricalImporter {
}
}
@@ -1,3 +1,2 @@
export { Meeting } from './meeting';
@@ -330,7 +330,6 @@ export class WebhookHandler {
}
}
private async createFailedMeetingRecord(params: unknown, error: string): Promise<void> {
try {
const twentyApiKey = process.env.TWENTY_API_KEY || '';
@@ -43,7 +43,6 @@ export default defineContentScript({
},
});
ctx.addEventListener(window, 'wxt:locationchange', ({newUrl, }) => {
const injectedBtn = document.querySelector('[data-id="twenty-btn"]');
if(personPattern.includes(newUrl) && !injectedBtn) ui.mount();
@@ -8,7 +8,6 @@ const StyledButton = styled.button`
--text-color: #0a66c2;
--bg-color: #00000000;
font-size: ${({theme}) => theme.spacing(3.5)};
font-weight: ${({theme}) => theme.font.weight.semiBold};
font-family: ${({theme}) => theme.font.family};
@@ -26,7 +25,6 @@ const StyledButton = styled.button`
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
transition-duration: 167ms;
&:hover {
background-color: var(--hover-bg-color);
color: var(--hover-color);
@@ -1,6 +1,5 @@
import { ThemeProvider } from '@emotion/react';
import type React from 'react';
import { THEME_DARK, ThemeContextProvider } from 'twenty-ui/theme';
import { ColorSchemeProvider } from 'twenty-ui/theme-constants';
type ThemeContextProps = {
children: React.ReactNode;
@@ -8,10 +7,6 @@ type ThemeContextProps = {
export const ThemeContext = ({ children }: ThemeContextProps) => {
return (
<ThemeProvider theme={THEME_DARK}>
<ThemeContextProvider theme={THEME_DARK}>
{children}
</ThemeContextProvider>
</ThemeProvider>
<ColorSchemeProvider colorScheme="dark">{children}</ColorSchemeProvider>
);
};
@@ -1,5 +1,3 @@
import type { ThemeType } from 'twenty-ui/theme';
declare module '@emotion/react' {
export interface Theme extends ThemeType {}
export interface Theme {}
}
+3 -13
View File
@@ -2,9 +2,7 @@ import { i18n } from '@lingui/core';
import { I18nProvider } from '@lingui/react';
import { type Preview } from '@storybook/react-vite';
import { initialize, mswLoader } from 'msw-storybook-addon';
import { useEffect } from 'react';
import { SOURCE_LOCALE } from 'twenty-shared/translations';
//import { useDarkMode } from 'storybook-dark-mode';
// eslint-disable-next-line no-restricted-imports
import { RootDecorator } from '../src/testing/decorators/RootDecorator';
@@ -13,7 +11,7 @@ import { resetJotaiStore } from '../src/modules/ui/utilities/state/jotai/jotaiSt
import 'react-loading-skeleton/dist/skeleton.css';
import 'twenty-ui/style.css';
import { THEME_LIGHT, ThemeContextProvider } from 'twenty-ui/theme';
import { ColorSchemeProvider } from 'twenty-ui/theme-constants';
// eslint-disable-next-line no-restricted-imports
import { messages as enMessages } from '../src/locales/generated/en';
@@ -60,23 +58,15 @@ initialize({
const preview: Preview = {
decorators: [
(Story) => {
// const theme = useDarkMode() ? THEME_DARK : THEME_LIGHT;
const theme = THEME_LIGHT;
useEffect(() => {
document.documentElement.className =
theme.name === 'dark' ? 'dark' : 'light';
}, [theme]);
return (
<I18nProvider i18n={i18n}>
<ThemeContextProvider theme={theme}>
<ColorSchemeProvider colorScheme="light">
<ClickOutsideListenerContext.Provider
value={{ excludedClickOutsideId: undefined }}
>
<Story />
</ClickOutsideListenerContext.Provider>
</ThemeContextProvider>
</ColorSchemeProvider>
</I18nProvider>
);
},
+1 -1
View File
@@ -1,5 +1,5 @@
<!doctype html>
<html lang="en" translate="no">
<html lang="en" translate="no" class="light">
<head>
<meta charset="UTF-8" />
File diff suppressed because one or more lines are too long
@@ -143,92 +143,74 @@ export type Mutation = {
updateWorkflowVersionStep: WorkflowAction;
};
export type MutationActivateWorkflowVersionArgs = {
workflowVersionId: Scalars['UUID'];
};
export type MutationComputeStepOutputSchemaArgs = {
input: ComputeStepOutputSchemaInput;
};
export type MutationCreateDraftFromWorkflowVersionArgs = {
input: CreateDraftFromWorkflowVersionInput;
};
export type MutationCreateWorkflowVersionEdgeArgs = {
input: CreateWorkflowVersionEdgeInput;
};
export type MutationCreateWorkflowVersionStepArgs = {
input: CreateWorkflowVersionStepInput;
};
export type MutationDeactivateWorkflowVersionArgs = {
workflowVersionId: Scalars['UUID'];
};
export type MutationDeleteWorkflowVersionEdgeArgs = {
input: CreateWorkflowVersionEdgeInput;
};
export type MutationDeleteWorkflowVersionStepArgs = {
input: DeleteWorkflowVersionStepInput;
};
export type MutationDismissReconnectAccountBannerArgs = {
connectedAccountId: Scalars['UUID'];
};
export type MutationDuplicateWorkflowArgs = {
input: DuplicateWorkflowInput;
};
export type MutationDuplicateWorkflowVersionStepArgs = {
input: DuplicateWorkflowVersionStepInput;
};
export type MutationRunWorkflowVersionArgs = {
input: RunWorkflowVersionInput;
};
export type MutationStopWorkflowRunArgs = {
workflowRunId: Scalars['UUID'];
};
export type MutationSubmitFormStepArgs = {
input: SubmitFormStepInput;
};
export type MutationTestHttpRequestArgs = {
input: TestHttpRequestInput;
};
export type MutationUpdateWorkflowRunStepArgs = {
input: UpdateWorkflowRunStepInput;
};
export type MutationUpdateWorkflowVersionPositionsArgs = {
input: UpdateWorkflowVersionPositionsInput;
};
export type MutationUpdateWorkflowVersionStepArgs = {
input: UpdateWorkflowVersionStepInput;
};
@@ -254,49 +236,42 @@ export type Query = {
search: SearchResultConnection;
};
export type QueryGetTimelineCalendarEventsFromCompanyIdArgs = {
companyId: Scalars['UUID'];
page: Scalars['Int'];
pageSize: Scalars['Int'];
};
export type QueryGetTimelineCalendarEventsFromOpportunityIdArgs = {
opportunityId: Scalars['UUID'];
page: Scalars['Int'];
pageSize: Scalars['Int'];
};
export type QueryGetTimelineCalendarEventsFromPersonIdArgs = {
page: Scalars['Int'];
pageSize: Scalars['Int'];
personId: Scalars['UUID'];
};
export type QueryGetTimelineThreadsFromCompanyIdArgs = {
companyId: Scalars['UUID'];
page: Scalars['Int'];
pageSize: Scalars['Int'];
};
export type QueryGetTimelineThreadsFromOpportunityIdArgs = {
opportunityId: Scalars['UUID'];
page: Scalars['Int'];
pageSize: Scalars['Int'];
};
export type QueryGetTimelineThreadsFromPersonIdArgs = {
page: Scalars['Int'];
pageSize: Scalars['Int'];
personId: Scalars['UUID'];
};
export type QuerySearchArgs = {
after?: InputMaybe<Scalars['String']>;
excludedObjectNameSingulars?: InputMaybe<Array<Scalars['String']>>;
@@ -579,7 +554,6 @@ export type GetTimelineCalendarEventsFromCompanyIdQueryVariables = Exact<{
pageSize: Scalars['Int'];
}>;
export type GetTimelineCalendarEventsFromCompanyIdQuery = { __typename?: 'Query', getTimelineCalendarEventsFromCompanyId: { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, timelineCalendarEvents: Array<{ __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
export type GetTimelineCalendarEventsFromOpportunityIdQueryVariables = Exact<{
@@ -588,7 +562,6 @@ export type GetTimelineCalendarEventsFromOpportunityIdQueryVariables = Exact<{
pageSize: Scalars['Int'];
}>;
export type GetTimelineCalendarEventsFromOpportunityIdQuery = { __typename?: 'Query', getTimelineCalendarEventsFromOpportunityId: { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, timelineCalendarEvents: Array<{ __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
export type GetTimelineCalendarEventsFromPersonIdQueryVariables = Exact<{
@@ -597,7 +570,6 @@ export type GetTimelineCalendarEventsFromPersonIdQueryVariables = Exact<{
pageSize: Scalars['Int'];
}>;
export type GetTimelineCalendarEventsFromPersonIdQuery = { __typename?: 'Query', getTimelineCalendarEventsFromPersonId: { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, timelineCalendarEvents: Array<{ __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
export type ParticipantFragmentFragment = { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string };
@@ -612,7 +584,6 @@ export type GetTimelineThreadsFromCompanyIdQueryVariables = Exact<{
pageSize: Scalars['Int'];
}>;
export type GetTimelineThreadsFromCompanyIdQuery = { __typename?: 'Query', getTimelineThreadsFromCompanyId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
export type GetTimelineThreadsFromOpportunityIdQueryVariables = Exact<{
@@ -621,7 +592,6 @@ export type GetTimelineThreadsFromOpportunityIdQueryVariables = Exact<{
pageSize: Scalars['Int'];
}>;
export type GetTimelineThreadsFromOpportunityIdQuery = { __typename?: 'Query', getTimelineThreadsFromOpportunityId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
export type GetTimelineThreadsFromPersonIdQueryVariables = Exact<{
@@ -630,7 +600,6 @@ export type GetTimelineThreadsFromPersonIdQueryVariables = Exact<{
pageSize: Scalars['Int'];
}>;
export type GetTimelineThreadsFromPersonIdQuery = { __typename?: 'Query', getTimelineThreadsFromPersonId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
export type SearchQueryVariables = Exact<{
@@ -642,7 +611,6 @@ export type SearchQueryVariables = Exact<{
filter?: InputMaybe<ObjectRecordFilterInput>;
}>;
export type SearchQuery = { __typename?: 'Query', search: { __typename?: 'SearchResultConnection', edges: Array<{ __typename?: 'SearchResultEdge', cursor: string, node: { __typename?: 'SearchRecord', recordId: any, objectNameSingular: string, objectLabelSingular: string, label: string, imageUrl?: string | null, tsRankCD: number, tsRank: number } }>, pageInfo: { __typename?: 'SearchResultPageInfo', hasNextPage: boolean, endCursor?: string | null } } };
export type WorkflowDiffFragmentFragment = { __typename?: 'WorkflowVersionStepChanges', triggerDiff?: any | null, stepsDiff?: any | null };
@@ -651,119 +619,102 @@ export type ActivateWorkflowVersionMutationVariables = Exact<{
workflowVersionId: Scalars['UUID'];
}>;
export type ActivateWorkflowVersionMutation = { __typename?: 'Mutation', activateWorkflowVersion: boolean };
export type ComputeStepOutputSchemaMutationVariables = Exact<{
input: ComputeStepOutputSchemaInput;
}>;
export type ComputeStepOutputSchemaMutation = { __typename?: 'Mutation', computeStepOutputSchema: any };
export type CreateDraftFromWorkflowVersionMutationVariables = Exact<{
input: CreateDraftFromWorkflowVersionInput;
}>;
export type CreateDraftFromWorkflowVersionMutation = { __typename?: 'Mutation', createDraftFromWorkflowVersion: { __typename?: 'WorkflowVersionDTO', id: any, name: string, status: string, trigger?: any | null, steps?: any | null, createdAt: string, updatedAt: string } };
export type CreateWorkflowVersionEdgeMutationVariables = Exact<{
input: CreateWorkflowVersionEdgeInput;
}>;
export type CreateWorkflowVersionEdgeMutation = { __typename?: 'Mutation', createWorkflowVersionEdge: { __typename?: 'WorkflowVersionStepChanges', triggerDiff?: any | null, stepsDiff?: any | null } };
export type CreateWorkflowVersionStepMutationVariables = Exact<{
input: CreateWorkflowVersionStepInput;
}>;
export type CreateWorkflowVersionStepMutation = { __typename?: 'Mutation', createWorkflowVersionStep: { __typename?: 'WorkflowVersionStepChanges', triggerDiff?: any | null, stepsDiff?: any | null } };
export type DeactivateWorkflowVersionMutationVariables = Exact<{
workflowVersionId: Scalars['UUID'];
}>;
export type DeactivateWorkflowVersionMutation = { __typename?: 'Mutation', deactivateWorkflowVersion: boolean };
export type DeleteWorkflowVersionEdgeMutationVariables = Exact<{
input: CreateWorkflowVersionEdgeInput;
}>;
export type DeleteWorkflowVersionEdgeMutation = { __typename?: 'Mutation', deleteWorkflowVersionEdge: { __typename?: 'WorkflowVersionStepChanges', triggerDiff?: any | null, stepsDiff?: any | null } };
export type DeleteWorkflowVersionStepMutationVariables = Exact<{
input: DeleteWorkflowVersionStepInput;
}>;
export type DeleteWorkflowVersionStepMutation = { __typename?: 'Mutation', deleteWorkflowVersionStep: { __typename?: 'WorkflowVersionStepChanges', triggerDiff?: any | null, stepsDiff?: any | null } };
export type DuplicateWorkflowMutationVariables = Exact<{
input: DuplicateWorkflowInput;
}>;
export type DuplicateWorkflowMutation = { __typename?: 'Mutation', duplicateWorkflow: { __typename?: 'WorkflowVersionDTO', id: any, name: string, status: string, trigger?: any | null, steps?: any | null, createdAt: string, updatedAt: string, workflowId: any } };
export type DuplicateWorkflowVersionStepMutationVariables = Exact<{
input: DuplicateWorkflowVersionStepInput;
}>;
export type DuplicateWorkflowVersionStepMutation = { __typename?: 'Mutation', duplicateWorkflowVersionStep: { __typename?: 'WorkflowVersionStepChanges', triggerDiff?: any | null, stepsDiff?: any | null } };
export type RunWorkflowVersionMutationVariables = Exact<{
input: RunWorkflowVersionInput;
}>;
export type RunWorkflowVersionMutation = { __typename?: 'Mutation', runWorkflowVersion: { __typename?: 'RunWorkflowVersion', workflowRunId: any } };
export type StopWorkflowRunMutationVariables = Exact<{
workflowRunId: Scalars['UUID'];
}>;
export type StopWorkflowRunMutation = { __typename?: 'Mutation', stopWorkflowRun: { __typename: 'WorkflowRun', id: any, status: WorkflowRunStatusEnum } };
export type UpdateWorkflowRunStepMutationVariables = Exact<{
input: UpdateWorkflowRunStepInput;
}>;
export type UpdateWorkflowRunStepMutation = { __typename?: 'Mutation', updateWorkflowRunStep: { __typename?: 'WorkflowAction', id: any, name: string, type: WorkflowActionType, settings: any, valid: boolean, nextStepIds?: Array<any> | null, position?: { __typename?: 'WorkflowStepPosition', x: number, y: number } | null } };
export type UpdateWorkflowVersionStepMutationVariables = Exact<{
input: UpdateWorkflowVersionStepInput;
}>;
export type UpdateWorkflowVersionStepMutation = { __typename?: 'Mutation', updateWorkflowVersionStep: { __typename?: 'WorkflowAction', id: any, name: string, type: WorkflowActionType, settings: any, valid: boolean, nextStepIds?: Array<any> | null, position?: { __typename?: 'WorkflowStepPosition', x: number, y: number } | null } };
export type SubmitFormStepMutationVariables = Exact<{
input: SubmitFormStepInput;
}>;
export type SubmitFormStepMutation = { __typename?: 'Mutation', submitFormStep: boolean };
export type TestHttpRequestMutationVariables = Exact<{
input: TestHttpRequestInput;
}>;
export type TestHttpRequestMutation = { __typename?: 'Mutation', testHttpRequest: { __typename?: 'TestHttpRequest', success: boolean, message: string, result?: any | null, error?: any | null, status?: number | null, statusText?: string | null, headers?: any | null } };
export type UpdateWorkflowVersionPositionsMutationVariables = Exact<{
input: UpdateWorkflowVersionPositionsInput;
}>;
export type UpdateWorkflowVersionPositionsMutation = { __typename?: 'Mutation', updateWorkflowVersionPositions: boolean };
export const TimelineCalendarEventParticipantFragmentFragmentDoc = gql`
@@ -1,11 +1,11 @@
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { useLingui } from '@lingui/react/macro';
import { IconCopy, IconExclamationCircle } from 'twenty-ui/display';
import { useContext } from 'react';
import { ThemeContext } from 'twenty-ui/theme';
import {
resolveThemeVariableAsNumber,
themeCssVariables,
} from 'twenty-ui/theme-constants';
export const useCopyToClipboard = () => {
const { theme } = useContext(ThemeContext);
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
const { t } = useLingui();
@@ -28,7 +28,13 @@ export const useCopyToClipboard = () => {
enqueueSuccessSnackBar({
message: message || t`Copied to clipboard`,
options: {
icon: <IconCopy size={theme.icon.size.md} />,
icon: (
<IconCopy
size={resolveThemeVariableAsNumber(
themeCssVariables.icon.size.md,
)}
/>
),
duration: 2000,
},
});
+2
View File
@@ -3,6 +3,8 @@ import ReactDOM from 'react-dom/client';
import { App } from '@/app/components/App';
import 'react-loading-skeleton/dist/skeleton.css';
import 'twenty-ui/style.css';
import 'twenty-ui/theme-light.css';
import 'twenty-ui/theme-dark.css';
import './index.css';
const root = ReactDOM.createRoot(
@@ -5,9 +5,12 @@ import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/NavigationDrawerConstraints';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useContext } from 'react';
import { ANIMATION, ThemeContext } from 'twenty-ui/theme';
import { MainNavigationDrawerItemsSkeletonLoader } from '~/loading/components/MainNavigationDrawerItemsSkeletonLoader';
import {
resolveThemeVariable,
resolveThemeVariableAsNumber,
themeCssVariables,
} from 'twenty-ui/theme-constants';
const StyledAnimatedContainer = styled(motion.div)`
align-items: center;
@@ -48,8 +51,6 @@ const StyledSkeletonTitleContainer = styled.div`
export const LeftPanelSkeletonLoader = () => {
const isMobile = useIsMobile();
const { theme } = useContext(ThemeContext);
return (
<StyledAnimatedContainer
initial={false}
@@ -57,13 +58,21 @@ export const LeftPanelSkeletonLoader = () => {
width: isMobile ? 0 : NAVIGATION_DRAWER_CONSTRAINTS.default,
opacity: isMobile ? 0 : 1,
}}
transition={{ duration: ANIMATION.duration.fast }}
transition={{
duration: resolveThemeVariableAsNumber(
themeCssVariables.animation.duration.fast,
),
}}
>
<StyledItemsContainer>
<StyledSkeletonTitleContainer>
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
baseColor={resolveThemeVariable(
themeCssVariables.background.tertiary,
)}
highlightColor={resolveThemeVariable(
themeCssVariables.background.transparent.lighter,
)}
borderRadius={4}
>
<Skeleton
@@ -1,8 +1,10 @@
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { styled } from '@linaria/react';
import { useContext } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { ThemeContext } from 'twenty-ui/theme';
import {
resolveThemeVariable,
themeCssVariables,
} from 'twenty-ui/theme-constants';
const StyledSkeletonContainer = styled.div`
align-items: flex-start;
@@ -21,13 +23,13 @@ export const MainNavigationDrawerItemsSkeletonLoader = ({
title?: boolean;
length: number;
}) => {
const { theme } = useContext(ThemeContext);
return (
<StyledSkeletonContainer>
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
baseColor={resolveThemeVariable(themeCssVariables.background.tertiary)}
highlightColor={resolveThemeVariable(
themeCssVariables.background.transparent.lighter,
)}
borderRadius={4}
>
{title && (
@@ -1,9 +1,10 @@
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { styled } from '@linaria/react';
import { useContext } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
themeCssVariables,
resolveThemeVariable,
} from 'twenty-ui/theme-constants';
const StyledRightDrawerContainer = styled.div`
display: flex;
@@ -13,12 +14,12 @@ const StyledRightDrawerContainer = styled.div`
`;
const StyledSkeletonLoader = () => {
const { theme } = useContext(ThemeContext);
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
baseColor={resolveThemeVariable(themeCssVariables.background.tertiary)}
highlightColor={resolveThemeVariable(
themeCssVariables.background.transparent.lighter,
)}
borderRadius={4}
>
<Skeleton height={SKELETON_LOADER_HEIGHT_SIZES.standard.m} width={140} />
@@ -1,9 +1,11 @@
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { styled } from '@linaria/react';
import { useContext } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { ThemeContext } from 'twenty-ui/theme';
import { MOBILE_VIEWPORT, themeCssVariables } from 'twenty-ui/theme-constants';
import {
MOBILE_VIEWPORT,
themeCssVariables,
resolveThemeVariable,
} from 'twenty-ui/theme-constants';
const StyledMainContainer = styled.div`
background: ${themeCssVariables.background.noisy};
@@ -50,13 +52,13 @@ const StyledRightPanelFlexContainer = styled.div`
`;
const StyledSkeletonHeaderLoader = () => {
const { theme } = useContext(ThemeContext);
return (
<StyledHeaderContainer>
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
baseColor={resolveThemeVariable(themeCssVariables.background.tertiary)}
highlightColor={resolveThemeVariable(
themeCssVariables.background.transparent.lighter,
)}
borderRadius={4}
>
<Skeleton
@@ -69,12 +71,12 @@ const StyledSkeletonHeaderLoader = () => {
};
const StyledSkeletonAddLoader = () => {
const { theme } = useContext(ThemeContext);
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
baseColor={resolveThemeVariable(themeCssVariables.background.tertiary)}
highlightColor={resolveThemeVariable(
themeCssVariables.background.transparent.lighter,
)}
borderRadius={4}
>
<Skeleton width={132} height={SKELETON_LOADER_HEIGHT_SIZES.standard.s} />
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Lêers"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Het jy jou wagwoord vergeet?"
@@ -7382,11 +7383,6 @@ msgstr "Ongeldige URL. Klik op wysig om hierdie widget te konfigureer."
msgid "Invalid verification code. Please try again."
msgstr "Ongeldige verifikasiekode. Probeer asseblief weer."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Ongeldige werkruimte"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "مجلدات"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "نسيت كلمة المرور؟"
@@ -7382,11 +7383,6 @@ msgstr "عنوان URL غير صالح. انقر فوق تحرير لتكوين
msgid "Invalid verification code. Please try again."
msgstr "رمز التحقق غير صالح. الرجاء المحاولة مرة أخرى."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "مساحة العمل غير صالحة"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Carpetes"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Has oblidat la teva contrasenya?"
@@ -7382,11 +7383,6 @@ msgstr "URL invàlida. Feu clic a editar per configurar aquest widget."
msgid "Invalid verification code. Please try again."
msgstr "Codi de verificació no vàlid. Torna-ho a intentar."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Espai de treball no vàlid"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Složky"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Zapomněli jste heslo?"
@@ -7382,11 +7383,6 @@ msgstr "Neplatná adresa URL. Kliknutím na Upravit nakonfigurujte tento widget.
msgid "Invalid verification code. Please try again."
msgstr "Neplatný ověřovací kód. Prosím, zkuste to znovu."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Neplatný pracovní prostor"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Mapper"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Glemt din adgangskode?"
@@ -7382,11 +7383,6 @@ msgstr "Ugyldig URL. Klik på rediger for at konfigurere denne widget."
msgid "Invalid verification code. Please try again."
msgstr "Ugyldig verifikationskode. Prøv venligst igen."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Ugyldigt arbejdsområde"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Ordner"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Passwort vergessen?"
@@ -7382,11 +7383,6 @@ msgstr "Ungültige URL. Klicken Sie auf Bearbeiten, um dieses Widget zu konfigur
msgid "Invalid verification code. Please try again."
msgstr "Ungültiger Bestätigungscode. Bitte versuchen Sie es erneut."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Ungültiger Arbeitsbereich"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Φάκελοι"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Ξεχάσατε τον κωδικό σας;"
@@ -7382,11 +7383,6 @@ msgstr ""
msgid "Invalid verification code. Please try again."
msgstr "Μη έγκυρος κωδικός επαλήθευσης. Παρακαλώ δοκιμάστε ξανά."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Μη έγκυρος χώρος εργασίας"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6393,6 +6393,7 @@ msgstr "Folders"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Forgot your password?"
@@ -7377,11 +7378,6 @@ msgstr "Invalid URL. Click edit to configure this widget."
msgid "Invalid verification code. Please try again."
msgstr "Invalid verification code. Please try again."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Invalid workspace"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Carpetas"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "¿Olvidó su contraseña?"
@@ -7382,11 +7383,6 @@ msgstr "URL no válida. Haga clic en editar para configurar este widget."
msgid "Invalid verification code. Please try again."
msgstr "Código de verificación inválido. Por favor intenta de nuevo."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Espacio de trabajo no válido"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Kansiot"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Unohtuiko salasana?"
@@ -7382,11 +7383,6 @@ msgstr "Virheellinen URL-osoite. Määritä tämä pienoisohjelma valitsemalla M
msgid "Invalid verification code. Please try again."
msgstr "Virheellinen varmennuskoodi. Yritä uudelleen."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Virheellinen työtila"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Dossiers"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Mot de passe oublié ?"
@@ -7382,11 +7383,6 @@ msgstr "URL invalide. Cliquez sur modifier pour configurer ce widget."
msgid "Invalid verification code. Please try again."
msgstr "Code de vérification invalide. Veuillez réessayer."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Espace de travail invalide"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
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
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "תיקיות"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "שכחת את הסיסמה שלך?"
@@ -7382,11 +7383,6 @@ msgstr "כתובת URL לא תקינה. לחץ ערוך כדי להגדיר וו
msgid "Invalid verification code. Please try again."
msgstr "קוד אימות שגוי. אנא נסה שוב."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "סביבת עבודה לא חוקית"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Mappák"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Elfelejtette a jelszavát?"
@@ -7382,11 +7383,6 @@ msgstr "Érvénytelen URL. Kattintson a szerkesztésre a widget konfigurálásá
msgid "Invalid verification code. Please try again."
msgstr "Érvénytelen ellenőrző kód. Kérjük, próbálja újra."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Érvénytelen munkaterület"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Cartelle"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Hai dimenticato la password?"
@@ -7382,11 +7383,6 @@ msgstr "URL non valido. Fai clic su modifica per configurare questo widget."
msgid "Invalid verification code. Please try again."
msgstr "Codice di verifica non valido. Per favore, riprova."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Area di lavoro non valida"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "フォルダー"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "パスワードを忘れましたか?"
@@ -7382,11 +7383,6 @@ msgstr "無効なURLです。このウィジェットを構成するには「編
msgid "Invalid verification code. Please try again."
msgstr "無効な確認コードです。再試行してください。"
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "無効なワークスペース"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "폴더"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "비밀번호를 잊으셨나요?"
@@ -7382,11 +7383,6 @@ msgstr "잘못된 URL입니다. 이 위젯을 설정하려면 편집을 클릭
msgid "Invalid verification code. Please try again."
msgstr "잘못된 인증 코드입니다. 다시 시도하십시오."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "잘못된 작업 공간"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Mappen"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Wachtwoord vergeten?"
@@ -7382,11 +7383,6 @@ msgstr "Ongeldige URL. Klik op bewerken om deze widget te configureren."
msgid "Invalid verification code. Please try again."
msgstr "Ongeldige verificatiecode. Probeer het opnieuw."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Ongeldige werkruimte"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Mapper"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Glemt passordet ditt?"
@@ -7382,11 +7383,6 @@ msgstr "Ugyldig URL. Klikk på rediger for å konfigurere denne widgeten."
msgid "Invalid verification code. Please try again."
msgstr "Ugyldig verifiseringskode. Vennligst prøv igjen."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Ugyldig arbeidsområde"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Foldery"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Nie pamiętasz hasła?"
@@ -7382,11 +7383,6 @@ msgstr "Nieprawidłowy adres URL. Kliknij edytuj, aby skonfigurować ten widget.
msgid "Invalid verification code. Please try again."
msgstr "Nieprawidłowy kod weryfikacyjny. Spróbuj ponownie."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Nieprawidłowa przestrzeń robocza"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
@@ -6393,6 +6393,7 @@ msgstr ""
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr ""
@@ -7377,11 +7378,6 @@ msgstr ""
msgid "Invalid verification code. Please try again."
msgstr ""
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr ""
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Pastas"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Esqueceu sua senha?"
@@ -7382,11 +7383,6 @@ msgstr "URL inválida. Clique em editar para configurar este widget."
msgid "Invalid verification code. Please try again."
msgstr "Código de verificação inválido. Por favor, tente novamente."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Espaço de trabalho inválido"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Pastas"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Esqueceu-se da sua palavra-passe?"
@@ -7382,11 +7383,6 @@ msgstr "URL inválida. Clique em editar para configurar este widget."
msgid "Invalid verification code. Please try again."
msgstr "Código de verificação inválido. Por favor, tente novamente."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Espaço de trabalho inválido"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Foldere"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Ați uitat parola?"
@@ -7382,11 +7383,6 @@ msgstr "Adresă URL nevalidă. Faceți clic pe editare pentru a configura acest
msgid "Invalid verification code. Please try again."
msgstr "Cod de verificare invalid. Te rog încearcă din nou."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Spațiu de lucru nevalid"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
Binary file not shown.
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Фасцикле"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Заборавили сте лозинку?"
@@ -7382,11 +7383,6 @@ msgstr "Неважећи УРЛ. Кликните на „Измени“ да
msgid "Invalid verification code. Please try again."
msgstr "Неправилан код верификације. Молимо покушајте поново."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Неважећа радна површина"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Mappar"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Glömt ditt lösenord?"
@@ -7382,11 +7383,6 @@ msgstr "Ogiltig URL. Klicka på redigera för att konfigurera denna widget."
msgid "Invalid verification code. Please try again."
msgstr "Ogiltig verifieringskod. Var god försök igen."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Ogiltig arbetsyta"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Klasörler"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Parolanızı mı unuttunuz?"
@@ -7382,11 +7383,6 @@ msgstr "Geçersiz URL. Bu widgetı yapılandırmak için düzenle'ye tıklayın.
msgid "Invalid verification code. Please try again."
msgstr "Geçersiz doğrulama kodu. Lütfen tekrar deneyin."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Geçersiz çalışma alanı"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Папки"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Забули свій пароль?"
@@ -7382,11 +7383,6 @@ msgstr "Недійсна URL-адреса. Натисніть «Редагува
msgid "Invalid verification code. Please try again."
msgstr "Неправильний код підтвердження. Спробуйте ще раз."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Недійсний робочий простір"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "Thư mục"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "Bạn quên mật khẩu à?"
@@ -7382,11 +7383,6 @@ msgstr "URL không hợp lệ. Nhấn chỉnh sửa để cấu hình tiện íc
msgid "Invalid verification code. Please try again."
msgstr "Mã xác minh không hợp lệ. Vui lòng thử lại."
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "Không gian làm việc không hợp lệ"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "文件夹"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "忘记密码?"
@@ -7382,11 +7383,6 @@ msgstr "无效的 URL。点击编辑以配置此小部件。"
msgid "Invalid verification code. Please try again."
msgstr "无效的验证码。请再试一次。"
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "无效的工作空间"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
+1 -5
View File
@@ -6398,6 +6398,7 @@ msgstr "資料夾"
#. js-lingui-id: glx6on
#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
#: src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx
msgid "Forgot your password?"
msgstr "忘記密碼?"
@@ -7382,11 +7383,6 @@ msgstr "URL 無效。點擊編輯以配置此小工具。"
msgid "Invalid verification code. Please try again."
msgstr "驗證碼無效。請再試一次。"
#. js-lingui-id: K8XJhc
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
msgid "Invalid workspace"
msgstr "無效的工作區"
#. js-lingui-id: ZR1dJ4
#: src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/WorkspacesForSignUp.tsx
msgid "Invitations"
@@ -3,7 +3,10 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { styled } from '@linaria/react';
import { motion } from 'framer-motion';
import { useContext } from 'react';
import { ThemeContext } from 'twenty-ui/theme';
import {
resolveThemeVariable,
themeCssVariables,
} from 'twenty-ui/theme-constants';
const StyledActionContainer = styled(motion.div)`
display: flex;
@@ -13,8 +16,6 @@ const StyledActionContainer = styled(motion.div)`
export const PageHeaderActionMenuButtons = () => {
const { actions } = useContext(ActionMenuContext);
const { theme } = useContext(ThemeContext);
const pinnedActions = actions.filter((entry) => entry.isPinned).toReversed();
const actionsWithPositionForAnimation = pinnedActions.map(
@@ -34,7 +35,9 @@ export const PageHeaderActionMenuButtons = () => {
animate={{ width: 'unset', opacity: 1 }}
exit={{ width: 0, opacity: 0 }}
transition={{
duration: theme.animation.duration.instant,
duration: resolveThemeVariable(
themeCssVariables.animation.duration.instant,
),
ease: 'easeInOut',
}}
>
@@ -1,12 +1,13 @@
import { useContext } from 'react';
import { styled } from '@linaria/react';
import { differenceInSeconds, endOfDay, format } from 'date-fns';
import { CalendarEventRow } from '@/activities/calendar/components/CalendarEventRow';
import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate';
import { CardContent } from 'twenty-ui/layout';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
themeCssVariables,
resolveThemeVariable,
} from 'twenty-ui/theme-constants';
import { type TimelineCalendarEvent } from '~/generated/graphql';
type CalendarDayCardContentProps = {
@@ -14,12 +15,14 @@ type CalendarDayCardContentProps = {
divider?: boolean;
};
const StyledCardContent = styled(CardContent)`
align-items: flex-start;
display: flex;
flex-direction: row;
gap: ${themeCssVariables.spacing[3]};
padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[3]};
const StyledCardContentContainer = styled.div`
> div {
align-items: flex-start;
display: flex;
flex-direction: row;
gap: ${themeCssVariables.spacing[3]};
padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[3]};
}
`;
const StyledDayContainer = styled.div`
@@ -45,7 +48,7 @@ const StyledEvents = styled.div`
gap: ${themeCssVariables.spacing[3]};
`;
const StyledEventRow = styled(CalendarEventRow)`
const StyledEventRowWrapper = styled.div`
flex: 1 0 auto;
`;
@@ -53,8 +56,6 @@ export const CalendarDayCardContent = ({
calendarEvents,
divider,
}: CalendarDayCardContentProps) => {
const { theme } = useContext(ThemeContext);
const endOfDayDate = endOfDay(getCalendarEventStartDate(calendarEvents[0]));
const dayEndsIn = differenceInSeconds(endOfDayDate, Date.now());
@@ -63,32 +64,39 @@ export const CalendarDayCardContent = ({
const upcomingDayCardContentVariants = {
upcoming: {},
ended: { backgroundColor: theme.background.primary },
ended: {
backgroundColor: resolveThemeVariable(
themeCssVariables.background.primary,
),
},
};
return (
<StyledCardContent
divider={divider}
initial="upcoming"
animate="ended"
variants={upcomingDayCardContentVariants}
transition={{
delay: Math.max(0, dayEndsIn),
duration: theme.animation.duration.fast,
}}
>
<StyledDayContainer>
<StyledWeekDay>{weekDayLabel}</StyledWeekDay>
<StyledMonthDay>{monthDayLabel}</StyledMonthDay>
</StyledDayContainer>
<StyledEvents>
{calendarEvents.map((calendarEvent) => (
<StyledEventRow
key={calendarEvent.id}
calendarEvent={calendarEvent}
/>
))}
</StyledEvents>
</StyledCardContent>
<StyledCardContentContainer>
<CardContent
divider={divider}
initial="upcoming"
animate="ended"
variants={upcomingDayCardContentVariants}
transition={{
delay: Math.max(0, dayEndsIn),
duration: resolveThemeVariable(
themeCssVariables.animation.duration.fast,
),
}}
>
<StyledDayContainer>
<StyledWeekDay>{weekDayLabel}</StyledWeekDay>
<StyledMonthDay>{monthDayLabel}</StyledMonthDay>
</StyledDayContainer>
<StyledEvents>
{calendarEvents.map((calendarEvent) => (
<StyledEventRowWrapper key={calendarEvent.id}>
<CalendarEventRow calendarEvent={calendarEvent} />
</StyledEventRowWrapper>
))}
</StyledEvents>
</CardContent>
</StyledCardContentContainer>
);
};
@@ -85,9 +85,11 @@ const StyledFields = styled.div`
width: 100%;
`;
const StyledPropertyBox = styled(PropertyBox)`
height: ${themeCssVariables.spacing[6]};
width: 100%;
const StyledPropertyBoxWrapper = styled.div`
> div {
height: ${themeCssVariables.spacing[6]};
width: 100%;
}
`;
export const CalendarEventDetails = ({
@@ -165,35 +167,37 @@ export const CalendarEventDetails = ({
});
return (
<StyledPropertyBox key={fieldMetadataItem.id}>
<FieldContext.Provider
value={{
recordId: calendarEvent.id,
isLabelIdentifier: false,
fieldDefinition: formatFieldMetadataItemAsFieldDefinition({
field: fieldMetadataItem,
objectMetadataItem,
showLabel: true,
labelWidth: 72,
}),
useUpdateRecord: useUpdateOneCalendarEventRecordMutation,
maxWidth: 300,
isRecordFieldReadOnly: isReadOnly,
}}
>
<RecordFieldComponentInstanceContext.Provider
<StyledPropertyBoxWrapper key={fieldMetadataItem.id}>
<PropertyBox>
<FieldContext.Provider
value={{
instanceId: getRecordFieldInputInstanceId({
recordId: calendarEvent.id,
fieldName: fieldMetadataItem.name,
prefix: INPUT_ID_PREFIX,
recordId: calendarEvent.id,
isLabelIdentifier: false,
fieldDefinition: formatFieldMetadataItemAsFieldDefinition({
field: fieldMetadataItem,
objectMetadataItem,
showLabel: true,
labelWidth: 72,
}),
useUpdateRecord: useUpdateOneCalendarEventRecordMutation,
maxWidth: 300,
isRecordFieldReadOnly: isReadOnly,
}}
>
<RecordInlineCell />
</RecordFieldComponentInstanceContext.Provider>
</FieldContext.Provider>
</StyledPropertyBox>
<RecordFieldComponentInstanceContext.Provider
value={{
instanceId: getRecordFieldInputInstanceId({
recordId: calendarEvent.id,
fieldName: fieldMetadataItem.name,
prefix: INPUT_ID_PREFIX,
}),
}}
>
<RecordInlineCell />
</RecordFieldComponentInstanceContext.Provider>
</FieldContext.Provider>
</PropertyBox>
</StyledPropertyBoxWrapper>
);
};
@@ -1,40 +1,52 @@
import { useContext } from 'react';
import { styled } from '@linaria/react';
import { Trans } from '@lingui/react/macro';
import { IconLock } from 'twenty-ui/display';
import { Card, CardContent } from 'twenty-ui/layout';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
resolveThemeVariableAsNumber,
themeCssVariables,
} from 'twenty-ui/theme-constants';
const StyledVisibilityCard = styled(Card)`
color: ${themeCssVariables.font.color.light};
const StyledVisibilityCardContainer = styled.div`
flex: 1;
border-color: ${themeCssVariables.border.color.light};
transition: color ${themeCssVariables.animation.duration.normal} ease;
width: 100%;
> div {
color: ${themeCssVariables.font.color.light};
border-color: ${themeCssVariables.border.color.light};
transition: color ${themeCssVariables.animation.duration.normal} ease;
}
`;
const StyledVisibilityCardContent = styled(CardContent)`
align-items: center;
background-color: ${themeCssVariables.background.transparent.lighter};
box-sizing: border-box;
display: flex;
font-size: ${themeCssVariables.font.size.sm};
font-weight: ${themeCssVariables.font.weight.medium};
gap: ${themeCssVariables.spacing[1]};
height: ${themeCssVariables.spacing[6]};
padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]};
const StyledVisibilityCardContentContainer = styled.div`
> div {
align-items: center;
background-color: ${themeCssVariables.background.transparent.lighter};
box-sizing: border-box;
display: flex;
font-size: ${themeCssVariables.font.size.sm};
font-weight: ${themeCssVariables.font.weight.medium};
gap: ${themeCssVariables.spacing[1]};
height: ${themeCssVariables.spacing[6]};
padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]};
}
`;
export const CalendarEventNotSharedContent = () => {
const { theme } = useContext(ThemeContext);
return (
<StyledVisibilityCard>
<StyledVisibilityCardContent>
<IconLock size={theme.icon.size.sm} />
<Trans>Not shared</Trans>
</StyledVisibilityCardContent>
</StyledVisibilityCard>
<StyledVisibilityCardContainer>
<Card>
<StyledVisibilityCardContentContainer>
<CardContent>
<IconLock
size={resolveThemeVariableAsNumber(
themeCssVariables.icon.size.sm,
)}
/>
<Trans>Not shared</Trans>
</CardContent>
</StyledVisibilityCardContentContainer>
</Card>
</StyledVisibilityCardContainer>
);
};
@@ -1,4 +1,4 @@
import { useContext, useRef } from 'react';
import { useRef } from 'react';
import { styled } from '@linaria/react';
import { type CalendarEventParticipant } from '@/activities/calendar/types/CalendarEventParticipant';
@@ -7,8 +7,10 @@ import { ParticipantChip } from '@/activities/components/ParticipantChip';
import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList';
import { IconCheck, IconQuestionMark, IconX } from 'twenty-ui/display';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
resolveThemeVariableAsNumber,
themeCssVariables,
} from 'twenty-ui/theme-constants';
const StyledInlineCellBaseContainer = styled.div`
align-items: center;
@@ -22,9 +24,11 @@ const StyledInlineCellBaseContainer = styled.div`
user-select: none;
`;
const StyledPropertyBox = styled(PropertyBox)`
height: ${themeCssVariables.spacing[6]};
width: 100%;
const StyledPropertyBoxWrapper = styled.div`
> div {
height: ${themeCssVariables.spacing[6]};
width: 100%;
}
`;
const StyledIconContainer = styled.div`
@@ -65,12 +69,22 @@ export const CalendarEventParticipantsResponseStatusField = ({
responseStatus: 'Yes' | 'Maybe' | 'No';
participants: CalendarEventParticipant[];
}) => {
const { theme } = useContext(ThemeContext);
const Icon = {
Yes: <IconCheck stroke={theme.icon.stroke.sm} />,
Maybe: <IconQuestionMark stroke={theme.icon.stroke.sm} />,
No: <IconX stroke={theme.icon.stroke.sm} />,
Yes: (
<IconCheck
stroke={resolveThemeVariableAsNumber(themeCssVariables.icon.stroke.sm)}
/>
),
Maybe: (
<IconQuestionMark
stroke={resolveThemeVariableAsNumber(themeCssVariables.icon.stroke.sm)}
/>
),
No: (
<IconX
stroke={resolveThemeVariableAsNumber(themeCssVariables.icon.stroke.sm)}
/>
),
}[responseStatus];
// We want to display external participants first
@@ -88,19 +102,21 @@ export const CalendarEventParticipantsResponseStatusField = ({
));
return (
<StyledPropertyBox>
<StyledInlineCellBaseContainer>
<StyledLabelAndIconContainer>
<StyledIconContainer>{Icon}</StyledIconContainer>
<StyledPropertyBoxWrapper>
<PropertyBox>
<StyledInlineCellBaseContainer>
<StyledLabelAndIconContainer>
<StyledIconContainer>{Icon}</StyledIconContainer>
<StyledLabelContainer width={72}>
<EllipsisDisplay>{responseStatus}</EllipsisDisplay>
</StyledLabelContainer>
</StyledLabelAndIconContainer>
<StyledDiv ref={participantsContainerRef}>
<ExpandableList isChipCountDisplayed>{styledChips}</ExpandableList>
</StyledDiv>
</StyledInlineCellBaseContainer>
</StyledPropertyBox>
<StyledLabelContainer width={72}>
<EllipsisDisplay>{responseStatus}</EllipsisDisplay>
</StyledLabelContainer>
</StyledLabelAndIconContainer>
<StyledDiv ref={participantsContainerRef}>
<ExpandableList isChipCountDisplayed>{styledChips}</ExpandableList>
</StyledDiv>
</StyledInlineCellBaseContainer>
</PropertyBox>
</StyledPropertyBoxWrapper>
);
};
@@ -1,4 +1,3 @@
import { useContext } from 'react';
import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
import { format } from 'date-fns';
@@ -16,8 +15,10 @@ import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEv
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useOpenCalendarEventInCommandMenu } from '@/command-menu/hooks/useOpenCalendarEventInCommandMenu';
import { IconArrowRight } from 'twenty-ui/display';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
resolveThemeVariableAsNumber,
themeCssVariables,
} from 'twenty-ui/theme-constants';
type CalendarEventRowProps = {
calendarEvent: TimelineCalendarEvent;
@@ -76,7 +77,6 @@ export const CalendarEventRow = ({
calendarEvent,
className,
}: CalendarEventRowProps) => {
const { theme } = useContext(ThemeContext);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const { openCalendarEventInCommandMenu } =
useOpenCalendarEventInCommandMenu();
@@ -114,7 +114,11 @@ export const CalendarEventRow = ({
{startTimeLabel}
{endTimeLabel && (
<>
<IconArrowRight size={theme.icon.size.sm} />
<IconArrowRight
size={resolveThemeVariableAsNumber(
themeCssVariables.icon.size.sm,
)}
/>
{endTimeLabel}
</>
)}
@@ -2,16 +2,20 @@ import { styled } from '@linaria/react';
import { Card } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledList = styled(Card)`
& > :not(:last-child) {
border-bottom: 1px solid ${themeCssVariables.border.color.light};
}
const StyledListContainer = styled.div`
width: calc(100% - 2px);
overflow: auto;
> div {
overflow: auto;
& > :not(:last-child) {
border-bottom: 1px solid ${themeCssVariables.border.color.light};
}
}
`;
export const ActivityList = ({ children }: React.PropsWithChildren) => {
return <StyledList>{children}</StyledList>;
return (
<StyledListContainer>
<Card>{children}</Card>
</StyledListContainer>
);
};
@@ -3,15 +3,17 @@ import React from 'react';
import { CardContent } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledRowContent = styled(CardContent)`
align-items: center;
display: flex;
gap: ${themeCssVariables.spacing[2]};
height: ${themeCssVariables.spacing[12]};
padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[4]};
const StyledRowContentContainer = styled.div`
> div {
align-items: center;
display: flex;
gap: ${themeCssVariables.spacing[2]};
height: ${themeCssVariables.spacing[12]};
padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[4]};
&[data-clickable='false'] {
cursor: default;
&[data-clickable='false'] {
cursor: default;
}
}
`;
@@ -30,8 +32,10 @@ export const ActivityRow = ({
};
return (
<StyledRowContent onClick={handleClick} isClickable={disabled !== true}>
{children}
</StyledRowContent>
<StyledRowContentContainer>
<CardContent onClick={handleClick} isClickable={disabled !== true}>
{children}
</CardContent>
</StyledRowContentContainer>
);
};
@@ -7,7 +7,7 @@ import { RecordChip } from '@/object-record/components/RecordChip';
import { Avatar } from 'twenty-ui/display';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledAvatar = styled(Avatar)`
const StyledAvatarContainer = styled.div`
margin-right: ${themeCssVariables.spacing[1]};
`;
@@ -67,12 +67,14 @@ export const ParticipantChip = ({
/>
) : (
<StyledChip>
<StyledAvatar
avatarUrl={avatarUrl}
type="rounded"
placeholder={displayName}
size="sm"
/>
<StyledAvatarContainer>
<Avatar
avatarUrl={avatarUrl}
type="rounded"
placeholder={displayName}
size="sm"
/>
</StyledAvatarContainer>
<StyledSenderName variant={variant}>{displayName}</StyledSenderName>
</StyledChip>
)}
@@ -1,8 +1,9 @@
import { useContext } from 'react';
import { styled } from '@linaria/react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
themeCssVariables,
resolveThemeVariable,
} from 'twenty-ui/theme-constants';
const StyledSkeletonContainer = styled.div`
align-items: center;
@@ -43,12 +44,12 @@ export const SKELETON_LOADER_HEIGHT_SIZES = {
};
const SkeletonColumnLoader = ({ height }: { height: number }) => {
const { theme } = useContext(ThemeContext);
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
baseColor={resolveThemeVariable(themeCssVariables.background.tertiary)}
highlightColor={resolveThemeVariable(
themeCssVariables.background.transparent.lighter,
)}
borderRadius={80}
>
<Skeleton width={24} height={height} />
@@ -61,15 +62,16 @@ export const SkeletonLoader = ({
}: {
withSubSections?: boolean;
}) => {
const { theme } = useContext(ThemeContext);
const skeletonItems = Array.from({ length: 3 }).map((_, index) => ({
id: `skeleton-item-${index}`,
}));
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
baseColor={resolveThemeVariable(themeCssVariables.background.tertiary)}
highlightColor={resolveThemeVariable(
themeCssVariables.background.transparent.lighter,
)}
borderRadius={4}
>
<StyledSkeletonContainer>
@@ -1,9 +1,10 @@
import { useContext } from 'react';
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { AppTooltip, IconLock, TooltipDelay } from 'twenty-ui/display';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
resolveThemeVariableAsNumber,
themeCssVariables,
} from 'twenty-ui/theme-constants';
import { MessageChannelVisibility } from '~/generated/graphql';
const StyledContainer = styled.div<{ isCompact?: boolean }>`
@@ -35,14 +36,15 @@ export const EmailThreadNotShared = ({
visibility,
}: EmailThreadNotSharedProps) => {
const { t } = useLingui();
const { theme } = useContext(ThemeContext);
const containerId = 'email-thread-not-shared';
const isCompact = visibility === MessageChannelVisibility.SUBJECT;
return (
<>
<StyledContainer id={containerId} isCompact={isCompact}>
<IconLock size={theme.icon.size.sm} />
<IconLock
size={resolveThemeVariableAsNumber(themeCssVariables.icon.size.sm)}
/>
{t`Not shared`}
</StyledContainer>
{visibility === MessageChannelVisibility.SUBJECT && (
@@ -1,12 +1,13 @@
import { useContext } from 'react';
import { styled } from '@linaria/react';
import { ActivityRow } from '@/activities/components/ActivityRow';
import { EmailThreadNotShared } from '@/activities/emails/components/EmailThreadNotShared';
import { useOpenEmailThreadInCommandMenu } from '@/command-menu/hooks/useOpenEmailThreadInCommandMenu';
import { Avatar } from 'twenty-ui/display';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
themeCssVariables,
resolveThemeVariable,
} from 'twenty-ui/theme-constants';
import {
MessageChannelVisibility,
type TimelineThread,
@@ -107,8 +108,6 @@ export const EmailThreadPreview = ({ thread }: EmailThreadPreviewProps) => {
};
const isDisabled = visibility !== MessageChannelVisibility.SHARE_EVERYTHING;
const { theme } = useContext(ThemeContext);
return (
<ActivityRow onClick={handleThreadClick} disabled={isDisabled}>
<StyledHeading unread={!thread.read}>
@@ -141,9 +140,15 @@ export const EmailThreadPreview = ({ thread }: EmailThreadPreviewProps) => {
avatarUrl={finalAvatarUrl}
placeholder={finalDisplayedName}
type="rounded"
color={isCountIcon ? theme.grayScale.gray11 : undefined}
color={
isCountIcon
? resolveThemeVariable(themeCssVariables.grayScale.gray11)
: undefined
}
backgroundColor={
isCountIcon ? theme.grayScale.gray2 : undefined
isCountIcon
? resolveThemeVariable(themeCssVariables.grayScale.gray2)
: undefined
}
/>
</StyledAvatarWrapper>
@@ -38,9 +38,11 @@ const StyledContainer = styled.div`
overflow: auto;
`;
const StyledH1Title = styled(H1Title)`
display: flex;
gap: ${themeCssVariables.spacing[2]};
const StyledH1TitleWrapper = styled.div`
> div {
display: flex;
gap: ${themeCssVariables.spacing[2]};
}
`;
const StyledEmailCount = styled.span`
@@ -107,15 +109,17 @@ export const EmailsCard = () => {
return (
<StyledContainer>
<Section>
<StyledH1Title
title={
<>
<Trans>Inbox</Trans>{' '}
<StyledEmailCount>{totalNumberOfThreads}</StyledEmailCount>
</>
}
fontColor={H1TitleFontColor.Primary}
/>
<StyledH1TitleWrapper>
<H1Title
title={
<>
<Trans>Inbox</Trans>{' '}
<StyledEmailCount>{totalNumberOfThreads}</StyledEmailCount>
</>
}
fontColor={H1TitleFontColor.Primary}
/>
</StyledH1TitleWrapper>
{!firstQueryLoading && (
<ActivityList>
{timelineThreads?.map((thread: TimelineThread) => (
@@ -10,22 +10,23 @@ import { downloadFile } from '@/activities/files/utils/downloadFile';
import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { isAttachmentPreviewEnabledState } from '@/client-config/states/isAttachmentPreviewEnabledState';
import { ModalStatefulWrapper } from '@/ui/layout/modal/components/ModalStatefulWrapper';
import { ModalContent, ModalHeader } from 'twenty-ui/layout';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { ModalContent, ModalHeader } from 'twenty-ui/layout';
import { ActivityList } from '@/activities/components/ActivityList';
import {
type AttachmentWithFile,
filterAttachmentsWithFile,
} from '@/activities/files/utils/filterAttachmentsWithFile';
import { getAttachmentUrl } from '@/activities/utils/getAttachmentUrl';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
import { IconDownload, IconX } from 'twenty-ui/display';
import { IconButton } from 'twenty-ui/input';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
PermissionFlagType,
FeatureFlagKey,
} from '~/generated-metadata/graphql';
import { PermissionFlagType } from '~/generated-metadata/graphql';
import { AttachmentRow } from './AttachmentRow';
const DocumentViewer = lazy(() =>
@@ -122,16 +123,12 @@ export const AttachmentList = ({
const { uploadAttachmentFile } = useUploadAttachmentFile();
const [isDraggingFile, setIsDraggingFile] = useState(false);
const [previewedAttachment, setPreviewedAttachment] =
useState<Attachment | null>(null);
useState<AttachmentWithFile | null>(null);
const isAttachmentPreviewEnabled = useAtomStateValue(
isAttachmentPreviewEnabledState,
);
const isFilesFieldMigrated = useIsFeatureEnabled(
FeatureFlagKey.IS_FILES_FIELD_MIGRATED,
);
const hasDownloadPermission = useHasPermissionFlag(
PermissionFlagType.DOWNLOAD_FILE,
);
@@ -142,15 +139,7 @@ export const AttachmentList = ({
const { openModal, closeModal } = useModal();
const getAttachmentUrl = (attachment: Attachment) => {
const fileUrl = isFilesFieldMigrated
? attachment.file?.[0]?.url || attachment.fullPath
: attachment.fullPath;
assertIsDefinedOrThrow(fileUrl, new Error(t`File URL is not defined`));
return fileUrl;
};
const attachmentsWithFile = filterAttachmentsWithFile(attachments);
const onUploadFile = async (file: File) => {
await uploadAttachmentFile(file, targetableObject);
@@ -162,7 +151,7 @@ export const AttachmentList = ({
}
};
const handlePreview = (attachment: Attachment) => {
const handlePreview = (attachment: AttachmentWithFile) => {
if (!isAttachmentPreviewEnabled) return;
setPreviewedAttachment(attachment);
openModal(PREVIEW_MODAL_ID);
@@ -174,20 +163,18 @@ export const AttachmentList = ({
};
const handleDownload = () => {
if (!previewedAttachment) return;
downloadFile(
getAttachmentUrl(previewedAttachment),
previewedAttachment.name,
);
if (!isDefined(previewedAttachment)) return;
const attachmentUrl = getAttachmentUrl({ attachment: previewedAttachment });
downloadFile(attachmentUrl, previewedAttachment.name);
};
return (
<>
{attachments && attachments.length > 0 && (
{attachmentsWithFile && attachmentsWithFile.length > 0 && (
<StyledContainer>
<StyledTitleBar>
<StyledTitle>
{title} <StyledCount>{attachments.length}</StyledCount>
{title} <StyledCount>{attachmentsWithFile.length}</StyledCount>
</StyledTitle>
{button}
</StyledTitleBar>
@@ -201,7 +188,7 @@ export const AttachmentList = ({
/>
) : (
<ActivityList>
{attachments.map((attachment) => (
{attachmentsWithFile.map((attachment) => (
<AttachmentRow
key={attachment.id}
attachment={attachment}
@@ -261,7 +248,9 @@ export const AttachmentList = ({
>
<DocumentViewer
documentName={previewedAttachment.name}
documentUrl={getAttachmentUrl(previewedAttachment)}
documentUrl={getAttachmentUrl({
attachment: previewedAttachment,
})}
/>
</Suspense>
</ModalContent>
@@ -1,8 +1,6 @@
import { ActivityRow } from '@/activities/components/ActivityRow';
import { AttachmentDropdown } from '@/activities/files/components/AttachmentDropdown';
import { type Attachment } from '@/activities/files/types/Attachment';
import { downloadFile } from '@/activities/files/utils/downloadFile';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { useDestroyOneRecord } from '@/object-record/hooks/useDestroyOneRecord';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import {
@@ -11,21 +9,21 @@ import {
} from '@/object-record/record-field/ui/contexts/FieldContext';
import { getFileCategoryFromExtension } from '@/object-record/record-field/ui/utils/getFileCategoryFromExtension';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useContext, useState } from 'react';
import { styled } from '@linaria/react';
import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { type AttachmentWithFile } from '@/activities/files/utils/filterAttachmentsWithFile';
import { FileIcon } from '@/file/components/FileIcon';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui/display';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { isNavigationModifierPressed } from 'twenty-ui/utilities';
import {
FeatureFlagKey,
PermissionFlagType,
} from '~/generated-metadata/graphql';
resolveThemeVariableAsNumber,
themeCssVariables,
} from 'twenty-ui/theme-constants';
import { isNavigationModifierPressed } from 'twenty-ui/utilities';
import { PermissionFlagType } from '~/generated-metadata/graphql';
import { formatToHumanReadableDate } from '~/utils/date-utils';
import { getFileNameAndExtension } from '~/utils/file/getFileNameAndExtension';
@@ -77,42 +75,29 @@ const StyledLinkContainer = styled.div`
`;
type AttachmentRowProps = {
attachment: Attachment;
onPreview?: (attachment: Attachment) => void;
attachment: AttachmentWithFile;
onPreview?: (attachment: AttachmentWithFile) => void;
};
export const AttachmentRow = ({
attachment,
onPreview,
}: AttachmentRowProps) => {
const { theme } = useContext(ThemeContext);
const [isEditing, setIsEditing] = useState(false);
const isFilesFieldMigrated = useIsFeatureEnabled(
FeatureFlagKey.IS_FILES_FIELD_MIGRATED,
);
const hasDownloadPermission = useHasPermissionFlag(
PermissionFlagType.DOWNLOAD_FILE,
);
const { name: originalFileName, extension: attachmentFileExtension } =
getFileNameAndExtension(
isFilesFieldMigrated
? (attachment.file?.[0]?.label as string)
: attachment.name,
);
getFileNameAndExtension(attachment.file.label);
const [attachmentFileName, setAttachmentFileName] =
useState(originalFileName);
const fileCategory = isFilesFieldMigrated
? getFileCategoryFromExtension(attachment.file?.[0]?.extension)
: attachment.fileCategory;
const fileCategory = getFileCategoryFromExtension(attachment.file.extension);
const fileUrl = isFilesFieldMigrated
? (attachment.file?.[0]?.url as string) // TODO : fix attachment.file type after Files field migration
: attachment.fullPath;
const fileUrl = attachment.file.url;
const { destroyOneRecord: destroyOneAttachment } = useDestroyOneRecord({
objectNameSingular: CoreObjectNameSingular.Attachment,
@@ -138,16 +123,12 @@ export const AttachmentRow = ({
idToUpdate: attachment.id,
updateOneRecordInput: {
name: newFileName,
...(isFilesFieldMigrated && isDefined(attachment.file?.[0]?.fileId)
? {
file: [
{
fileId: attachment.file?.[0]?.fileId,
label: newFileName,
},
],
}
: {}),
file: [
{
fileId: attachment.file.fileId,
label: newFileName,
},
],
},
});
};
@@ -220,7 +201,11 @@ export const AttachmentRow = ({
</StyledLeftContent>
<StyledRightContent>
<StyledCalendarIconContainer>
<IconCalendar size={theme.icon.size.md} />
<IconCalendar
size={resolveThemeVariableAsNumber(
themeCssVariables.icon.size.md,
)}
/>
</StyledCalendarIconContainer>
{formatToHumanReadableDate(attachment.createdAt)}
<AttachmentDropdown
@@ -9,12 +9,14 @@ import DocViewer, { DocViewerRenderers } from '@cyntler/react-doc-viewer';
import '@cyntler/react-doc-viewer/dist/index.css';
import { styled } from '@linaria/react';
import { Trans, useLingui } from '@lingui/react/macro';
import { useContext, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { IconDownload } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
themeCssVariables,
resolveThemeVariable,
} from 'twenty-ui/theme-constants';
import { getFileNameAndExtension } from '~/utils/file/getFileNameAndExtension';
const MS_OFFICE_EXTENSIONS = [
@@ -201,7 +203,6 @@ export const DocumentViewer = ({
documentExtension,
}: DocumentViewerProps) => {
const { t } = useLingui();
const { theme } = useContext(ThemeContext);
const [csvPreview, setCsvPreview] = useState<CsvPreviewData | undefined>(
undefined,
);
@@ -319,8 +320,10 @@ export const DocumentViewer = ({
pluginRenderers={DocViewerRenderers}
style={{
height: '100%',
color: theme.font.color.primary,
backgroundColor: theme.background.primary,
color: resolveThemeVariable(themeCssVariables.font.color.primary),
backgroundColor: resolveThemeVariable(
themeCssVariables.background.primary,
),
}}
config={{
header: {
@@ -335,12 +338,20 @@ export const DocumentViewer = ({
},
}}
theme={{
primary: theme.background.primary,
secondary: theme.background.secondary,
tertiary: theme.background.tertiary,
textPrimary: theme.font.color.primary,
textSecondary: theme.font.color.secondary,
textTertiary: theme.font.color.tertiary,
primary: resolveThemeVariable(themeCssVariables.background.primary),
secondary: resolveThemeVariable(
themeCssVariables.background.secondary,
),
tertiary: resolveThemeVariable(themeCssVariables.background.tertiary),
textPrimary: resolveThemeVariable(
themeCssVariables.font.color.primary,
),
textSecondary: resolveThemeVariable(
themeCssVariables.font.color.secondary,
),
textTertiary: resolveThemeVariable(
themeCssVariables.font.color.tertiary,
),
disableThemeScrollbar: true,
}}
/>
@@ -1,12 +1,13 @@
import { useContext } from 'react';
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { useDropzone } from 'react-dropzone';
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
import { IconUpload } from 'twenty-ui/display';
import { ThemeContext } from 'twenty-ui/theme';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
resolveThemeVariableAsNumber,
themeCssVariables,
} from 'twenty-ui/theme-constants';
const StyledContainer = styled.div`
align-items: center;
@@ -35,9 +36,10 @@ const StyledUploadDragSubTitle = styled.div`
line-height: ${themeCssVariables.text.lineHeight.md};
`;
const StyledUploadIcon = styled(IconUpload)`
const StyledUploadIconContainer = styled.span`
color: ${themeCssVariables.font.color.tertiary};
margin-bottom: ${themeCssVariables.spacing[3]};
display: flex;
`;
type DropZoneProps = {
@@ -50,7 +52,6 @@ export const DropZone = ({
onUploadFiles,
}: DropZoneProps) => {
const { t } = useLingui();
const { theme } = useContext(ThemeContext);
const { maxFileSize } = useSpreadsheetImportInternal();
const { getRootProps, getInputProps, isDragActive } = useDropzone({
@@ -84,10 +85,16 @@ export const DropZone = ({
// eslint-disable-next-line react/jsx-props-no-spreading
{...getInputProps()}
/>
<StyledUploadIcon
stroke={theme.icon.stroke.sm}
size={theme.icon.size.lg}
/>
<StyledUploadIconContainer>
<IconUpload
stroke={resolveThemeVariableAsNumber(
themeCssVariables.icon.stroke.sm,
)}
size={resolveThemeVariableAsNumber(
themeCssVariables.icon.size.lg,
)}
/>
</StyledUploadIconContainer>
<StyledUploadDragTitle>{t`Upload files`}</StyledUploadDragTitle>
<StyledUploadDragSubTitle>
{t`Drag and Drop Here`}

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