Compare commits

...
Author SHA1 Message Date
Abdullah ac1fc1a65a refactor(website): drop the fill mode superseded by compact + dead shell defaults
After compact landed, ProductVisual's fill only ever co-occurred with compact,
which overrode everything fill did in the shell. Removed fill from AppPreviewFrame
(and its crop branches) and from ShellScene; fill now solely drives StyledRoot
filling the morph area. Also removed ShellScene's now-unreachable aspect-ratio /
max-height defaults (every instance is bleed or compact, so height is constant).
2026-06-07 05:47:57 +05:00
Abdullah 28e94a49ba fix(website): give the mobile AI section standard section top padding
On mobile the AI section is a normal stacked section (not the first below the
nav), so it now uses spacing(12) top padding to match TrustedBy/ProductFeature,
via a $secondary prop on MobileSection. The intro section keeps spacing(7.5).
2026-06-07 04:59:56 +05:00
Abdullah b7179a66e8 fix(website): render both hero layouts and CSS-toggle to kill the mobile jump
The product hero is statically prerendered as the desktop morph (200vh), so on
a phone it swapped to the stacked mobile layout after hydration and reflowed the
page. Now both the morph and mobile layouts render and are shown/hidden via CSS
@media, so neither side jumps when the viewport resolves — desktop unchanged.
Each side's WebGL halftone and the mobile AI autoplay are gated by visibility so
only the on-screen layout does the heavy work.
2026-06-07 04:11:24 +05:00
Abdullah babd52516b feat(website): lock the phone AI panel to a 320px chat width
Below 600px the panel-only window is capped at 320px and centered, so it reads
as a chat panel instead of stretching toward the 600px breakpoint.
2026-06-07 02:17:19 +05:00
Abdullah 2514f2d760 feat(website): panel-only AI section on phones (<600px)
Below 600px the CRM board and AI panel can't coexist, so the AI section
collapses to a full-width 'Ask AI' window: AppPreviewLayout short-circuits to
render only the aside, and AiPanel goes full-width/flush. 600-921 keeps the
compact board+panel; the desktop morph is unchanged.
2026-06-07 02:11:27 +05:00
Abdullah 7abdaac42b feat(website): compact the AI morph so the panel never bleeds off-screen
- ProductVisual/AppPreviewFrame: add a compact mode — fixed-height window that
  fits the viewport width (capped), no aspect-ratio, so the board flexes while
  the sidebar + AI panel stay legible. Used by both morph layers (intro + AI)
  so the wipe stays aligned, and by the mobile AI section.
- Remove the two md-breakpoint 'display: none' rules (AsideSlot + AiPanel) that
  hid the AI panel below 921px; with the compact window it now fits and renders.
2026-06-07 01:58:26 +05:00
Abdullah 726c956afe feat(website): bleed the Demo AppPreview
- ProductDemo: enable bleed on the static AppPreview (fixed 1040x676 window,
  bleeds right when narrow, centers when wide) and clip the section overflow so
  the bleed never causes horizontal page scroll.
- Drop PreviewRoot's leftover margin-bottom; the bleed window already owns its
  below-space (consistent with HomeHero), so the old aspect-era margin just
  double-stacked.
2026-06-06 23:05:24 +05:00
Abdullah 4792b49ade feat(website): bleed the ProductHero intro + align spacing with HomeHero
- ProductVisual: add a bleed mode (fixed 1040x676 window, no aspect/flex
  scaling) so the intro window holds full scale and bleeds right instead of
  aspect-shrinking. Enable it on the desktop + mobile intro instances.
- HeroVisualScroll: render the halftone background on mobile too (it was
  desktop-only), scoped to the visual area and stretched into the bottom space.
- Match ProductHero spacing to HomeHero: body margin, CTA-to-visual gap
  (row-gap on FullLayer + MobileSection), and the mobile top padding (the
  in-flow mobile branch no longer double-counts sticky-nav clearance).
  Replace raw px with theme.spacing.
2026-06-06 22:53:16 +05:00
Abdullah 0f4064d326 feat(website): bleed the HomeHero app window at fixed scale
- AppPreview: add a bleed mode (BleedShellScene) — fixed 1040x676 window box
  with margin auto (centers when it fits, bleeds right when narrower), constant
  section height, and a fixed below-window space. No aspect-ratio.
- AppWindow: fill the box (width INITIAL_MAX_WIDTH, height = parent) instead of
  capping to an aspect ratio, so the window stays full-scale and bleeds.
- HomeHero: opt into bleed.
- Terminal: anchor the AI chat to the fixed window box (no width-drift), tune its
  bottom/right offsets, and CSS-hide it below 1350px (no hydration flash).
- Update terminal-window-geometry offsets + test.
2026-06-06 20:03:22 +05:00
Abdullah 8c0a0f08ea fix(website): prevent demo AppPreview from overflowing on responsive widths
ProductDemo's grid wrappers used grid-template-columns: 1fr, whose auto min
floors the column at the AppPreview's intrinsic min-content width (from its
aspect-ratio + max-height). On mid widths the column blew out wider than the
container and the window overflowed right. Use minmax(0, 1fr) + min-width: 0
(matching HeroSection) so the column can shrink to fit.
2026-06-05 19:58:38 +05:00
Abdullah 1d1c3dc9f3 Fill the hero visual and full-bleed the halftone behind it
- ProductVisual/AppPreviewFrame: add a fill mode that crops the natural-aspect
  window to the available area (top-aligned, overflow) instead of stretching, so
  the visual fills the pinned frame without distortion. Mobile stays aspect-locked.
- HeroVisualScroll: make the pattern overlay full-bleed (inset:0) so the halftone
  covers the whole frame behind the visual instead of a fixed bottom band.
- use-product-background-halftone: map the image with a true cover (fill both
  axes, crop overflow) instead of cover-by-width, so the pattern reaches full
  height on tall viewports instead of letterboxing into a low band.
2026-06-05 18:51:20 +05:00
Abdullah 71a8142346 Open the AI panel on hero->AI scroll and fix tab focus ring
- AppPreviewLayout: render the right aside in a width-animated slot driven by
  asideProgress, so the board reflows smaller as the panel opens (instead of
  overlaying). Hidden below md to match AiPanel.
- ProductVisual: thread aiPanelProgress -> asideProgress.
- HeroVisualScroll: derive aiPanelProgress from morphProgress so the Ask AI
  panel slides open as the section wipes in, and start playback once it's open
  (thinking -> answer -> board builds as the result), so the section reads as AI.
- TabButton: preventDefault on mousedown so the :focus-visible ring no longer
  lingers after a pointer click while keyboard focus still shows it.
2026-06-05 16:46:47 +05:00
Abdullah.andGitHub 3b69047b83 Merge branch 'main' into website-product-hero 2026-06-05 14:35:41 +05:00
Abdullah.andGitHub b60a91a075 fix(website): render releases from local notes, drop GitHub gate (#21238)
The releases page gated visible notes on fetchLatestGithubReleaseTag();
when that unauthenticated GitHub call was rate-limited at build (common
on shared Cloudflare build IPs, no GITHUB_TOKEN), it returned null and
getVisibleReleaseNotes returned [], rendering 'No releases are visible
yet for the current published version' — the exact prod symptom.
force-static made each deploy a coin flip.

Committed MDX (+images) is the single source of truth, so gate
visibility on nothing: render all local notes deterministically with no
network call. Removes the dev/prod divergence and deletes the now-dead
fetch-latest-release-tag.ts and get-visible-releases.ts.
2026-06-05 08:59:40 +00:00
Charles BochetandGitHub cd540098f1 fix: pass reference_commit to Argos to resolve orphan PR builds (#21245)
## Summary

- Fixes Argos CI builds showing as "Orphan" (no reference branch) for PR
builds
- Computes the merge-base SHA between the PR head and `main` using the
GitHub API (`compareCommitsWithBasehead`) in the dispatch workflow
- Passes `reference_commit` in the `ci-privileged` dispatch payload so
it can be forwarded to the Argos upload API

## Context

PR builds on Argos were showing as "Orphan" because `ci-privileged`
(where the actual Argos upload happens) has no git history of the
`twenty` repo — it cannot compute the merge-base locally. Without a
`referenceCommit`, Argos can't determine which `main` build to compare
against.

The local `visual-diff.sh` script already passes
`ARGOS_REFERENCE_COMMIT` via `git merge-base HEAD main`, but the CI
pipeline was missing this. This PR adds equivalent logic using the
GitHub API (no checkout needed).

## Note for ci-privileged

The `upload-to-argos.ts` script in `ci-privileged` needs a corresponding
update to read `reference_commit` from the dispatch payload and pass it
as `referenceCommit` in the Argos API call:

```typescript
referenceCommit: process.env.REFERENCE_COMMIT || undefined,
```

## Test plan

- [ ] Verify the workflow runs successfully on a PR (merge-base step
computes a SHA)
- [ ] Confirm Argos PR builds are no longer marked as "Orphan" after the
ci-privileged counterpart is updated
2026-06-05 10:51:16 +02:00
Félix MalfaitandGitHub 1b30983307 fix(settings): gate the AI settings page on AI_SETTINGS, not the chat flag (#21239)
## Summary

Closes #21229.

The two AI role permissions behaved **opposite to their labels**. The
trap is that the flag's code name is the inverse of its UI label:

| `PermissionFlagType` | UI label | Section | Means |
|---|---|---|---|
| `AI` | **"Ask AI"** | Actions | End-user: chat with AI |
| `AI_SETTINGS` | **"AI"** | Member / settings | Admin: configure AI
agents |

Before this PR (on `main`):
- `AI` ("Ask AI", chat) gated **both** the AI chat **and** the AI
settings page.
- `AI_SETTINGS` ("AI", configure agents) gated **nothing** the user
could see.

So a chat-only user could reach the whole AI **configuration** page, and
toggling the "AI" settings permission did nothing — exactly the
misalignment reported in #21229.

## Root cause

`PermissionFlagType.AI` *reads* like "the AI permission", so it looks
like the natural gate for the AI settings page — but it's actually the
**chat** flag. The settings page (nav item + route) had been pointed at
`AI` in #21072 to match the Overview stats query
(`findWorkspaceAiStats`), which was itself mis-gated on `AI`. Both the
stats query and the rest of the settings surface are admin/config
features, so they belong on `AI_SETTINGS`.

## Changes

All three move the **AI settings surface** from the chat flag (`AI`) to
the settings flag (`AI_SETTINGS`); chat keeps following `AI`:

- `useSettingsNavigationItems.tsx` — AI nav item → `AI_SETTINGS`
- `SettingsRoutes.tsx` — AI settings route group → `AI_SETTINGS`
- `ai-workspace-stats.resolver.ts` — `findWorkspaceAiStats`
(settings-only, drives the Overview tab) → `AI_SETTINGS`

After this: the "AI" permission controls the AI settings page + its
Overview; the "Ask AI" permission controls the chat. Both toggles now
match their labels.

## Test plan

- [ ] Role with **only "Ask AI"** (`AI`): AI chat tabs/pane visible;
**Settings → AI is hidden** and the route is not reachable.
- [ ] Role with **only "AI"** (`AI_SETTINGS`): Settings → AI is visible,
Overview stats load; chat nav is hidden.
- [ ] Admin (both flags): everything works as before.

## Known follow-ups (out of scope — pre-existing, shared endpoints)

These remain on `AI` because they're shared with non-settings surfaces
and need either OR-gating or a resolver split, so a role with
`AI_SETTINGS` but **not** `AI` still can't use them yet:

- `getAiSystemPromptPreview` (Models/Prompts tabs) lives in the chat
resolver, class-gated `AI`; NestJS guards are additive so it can't be
cleanly method-overridden — it should be pulled into a settings
resolver.
- Agent reads `findManyAgents` / `findOneAgent` (agent create/edit
forms) are class-gated `AI` and shared with the **Workflow** editor and
**Roles** pages; these want a guard that accepts `AI ∨ AI_SETTINGS ∨
WORKFLOWS`.
2026-06-05 08:18:20 +00:00
martmullandGitHub 128d2d394d feat: allow apps to add view fields to existing views (defineViewField) (#21160)
## Summary

Lets a Twenty application add **view fields (columns) to an existing
view it does not own** — including standard views like the People index
view — without redeclaring/owning that view. This mirrors the existing,
working pattern by which an app adds a custom field to a standard object
via `defineField` + `objectUniversalIdentifier`.

The asymmetry being removed was purely in the manifest schema:
`ViewFieldManifest` only existed *nested* inside
`ViewManifest.fields[]`, so adding a view field forced declaring a
`ViewManifest` — which the sync treats as a view the app creates and
owns, and rejects when the UID is a standard view's. Validation,
persistence, the FK aggregator machinery, and uninstall cleanup were
already generic and cross-app-safe, so no engine changes were needed.

### Changes
- **twenty-shared:** new top-level `StandaloneViewFieldManifest`
(`ViewFieldManifest & { viewUniversalIdentifier }`),
`Manifest.viewFields`, and a `SyncableEntity.ViewField` member.
- **twenty-sdk:** `defineViewField` (validates `universalIdentifier` +
`viewUniversalIdentifier` + `fieldMetadataUniversalIdentifier`), CLI
manifest assembly of a top-level `viewFields` list, and `dev:add
viewField` scaffolding.
- **twenty-server:** one top-level loop over `manifest.viewFields` that
reuses the existing `fromViewFieldManifestToUniversalFlatViewField`
converter (already parameterized by `viewUniversalIdentifier`). No
validator/persistence/aggregator changes.

### Notes for maintainers
- Confirm the `Manifest.viewFields` optionality convention — implemented
as a **required** array to mirror `fields`/`views`.
- Two different apps adding a column for the same field to the same view
conflicts on the existing unique `(fieldMetadataId, viewId)` partial
index; the existing `flat-view-field-validator` duplicate check surfaces
this as a structured validation error.
- `dev:add viewField` scaffolding is included (was optional in the
plan).

## Test Plan
- [x] `twenty-shared` typecheck
- [x] `twenty-sdk` 364 unit tests + `buildManifest` assembly test
(rich-app fixture) + typecheck + prettier
- [x] `twenty-server` typecheck + `lint:diff-with-main`
- [x] **Server integration suite**
`successful-manifest-update-view-field.integration-spec.ts` (4/4):
- standalone view field attaches to the standard `allPeople` view
without recreating it (sync succeeds, no
`INVALID_VIEW_DATA`/`ENTITY_ALREADY_EXISTS`)
- uninstall removes the contributed column while the standard view + its
columns remain intact
  - duplicate `(view, field)` rejected with `METADATA_VALIDATION_FAILED`
  - unknown target view rejected
- [x] Sibling `successful-manifest-update-field.integration-spec.ts`
still green (no harness regression)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-05 08:06:30 +00:00
ff9b5a5cad chore: sync AI model catalog from models.dev (#21242)
Automated daily sync of `ai-providers.json` from
[models.dev](https://models.dev).

This PR updates pricing, context windows, and model availability based
on the latest data.
New models meeting inclusion criteria (tool calling, pricing data,
context limits) are added automatically.
Deprecated models are detected based on cost-efficiency within the same
model family.

**Please review before merging** — verify no critical models were
incorrectly deprecated.

Co-authored-by: FelixMalfait <6399865+FelixMalfait@users.noreply.github.com>
2026-06-05 09:22:38 +02:00
979047d004 fix: allow email change verification on self-hosted instances (#20123)
fixes #20117 

## Technical Details
Flow after fix:
1. User submits email change request
2. user.service.ts:517-524 calls sendVerificationEmail() with
verificationTrigger: EMAIL_UPDATE
3. Guard checks: verificationTrigger === SIGN_UP → false → guard skipped
4. Verification token generated, email rendered and sent via
emailService.send()
5. User receives confirmation email at new address
6. User clicks confirmation link → email update completes
---
Impact
- Minimal change: Only 3 lines modified in a single file
- No breaking changes: Sign-up verification behavior unchanged
- Security preserved: Email changes always require verification (correct
security behavior)
- Self-hosted friendly: Instance admins can disable sign-up verification
while keeping email change verification active

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-06-04 18:56:15 +00:00
EtienneandGitHub 8bd4cbc3fd fix(ai) - optim (#21233)
1. tool-registry.service.ts, Pass precomputed catalog to
resolveSchemas()

resolveSchemas() now accepts an optional precomputedCatalog parameter.
Both getToolsByName() and getToolInfo() pass the catalog they already
fetched, eliminating a redundant getCatalog() rebuild inside
resolveSchemas().

2. database-tool.provider.ts, Skip field lookup when schemas=false

When building the catalog index (includeSchemas=false),
getFlatFieldsFromFlatObjectMetadata() is no longer called for each of
the 25 objects. The hasGroupByToolInputSchema() check is also skipped,
group_by tools are always included in the index, with the real
eligibility check deferred to learn_tools time.

--> 100/150ms gain on learn/execute_tool execution
2026-06-04 17:27:25 +00:00
f899660a40 i18n - docs translations (#21237)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-06-04 19:24:06 +02:00
Paul RastoinandGitHub 0877ba2ffd Fix getApplicationSubAllFlatEntityMaps to prune unrelated appIds universal identifier aggregators (#21234)
# Introduction
Atm when computing the `fromAllFlatEntityMaps` we're retrieving all the
applicationIds related metadata entities to build a flat entity maps
scoped to them ( atm always the applicationId + twenty-standard
application id ) only inter app dependency we manage for the moment

A flat entity contains universal identifier aggregator to its related
entities

The issue was that the `getApplicationSubAllFlatEntityMaps` wasn't
pruning the aggregator by app

Now added a new process phase after the initial one that will check that
all the aggregators contains universal identifiers that has been
retrieve from the appId + appId standard intersection

## TDD test
Created a very human readable ( that's a joke ) test
2026-06-04 16:53:25 +00:00
Thomas TrompetteandGitHub 4e1cc2d831 fix: prevent workflow from disappearing after activation (#21231)
## Summary
- Fixes a regression from #21176 where activating a workflow caused it
to disappear until page refresh
- Root cause: when a draft is activated (status DRAFT→ACTIVE),
`useEffectiveDraftVersionId` incorrectly treated it as a discard because
the cached version was no longer DRAFT, filtering it from the versions
list
- Fix: only set `lastDiscardedDraftId` when `deletedAt` is actually set
on the cached version, not when the status simply changes

## Test plan
- [x] Open a workflow with a DRAFT version
- [x] Activate the workflow → verify it does NOT disappear
- [x] Discard a draft → verify header does NOT flicker between
DRAFT/ACTIVE
2026-06-04 16:42:05 +00:00
martmullGitHubcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
c2ca90c255 feat(sdk): add runAgent() to run app agents from logic functions (#21157)
<img width="948" height="593" alt="image"
src="https://github.com/user-attachments/assets/d990fa98-3cfd-469d-ab7f-0b2d4ccf3afc"
/>

<img width="1361" height="802" alt="image"
src="https://github.com/user-attachments/assets/1091f598-49f3-4c16-92ea-1e1c200181e2"
/>


## Add `runAgent()` to the Logic Function SDK

Lets an app's logic function run one of its own AI agents server-side
and get the result back synchronously — reusing the existing agent
executor instead of a new bespoke transport.

  ### Backend
- New **`runAgent` GraphQL mutation** (metadata schema) in
`ai-agent-execution`, wrapping the existing
`AgentAsyncExecutorService.executeAgent`. Scopes the agent lookup to the
calling
  application and runs it under an application auth context.
- New `@AuthApplication()` param decorator (mirrors `@AuthWorkspace()`)
— first GraphQL resolver authenticated by an **application access
token**.
- Guarded by `WorkspaceAuthGuard` +
`SettingsPermissionGuard(PermissionFlagType.AI)`: the app's role must
grant the `AI` permission flag.

  ### SDK
- `runAgent({ agentUniversalIdentifier, prompt })` posts the mutation to
`/metadata` with the app token via a new runtime GraphQL transport.
Returns `{ result, hasNoMoreAvailableCredits
  }`.
- Refactored the connections helpers onto a shared `postAppEndpoint`
util (removes duplicated transport logic).

  ### Frontend
- App install permission modal now shows an explicit consent line —
_"Run AI agents and bill AI credits to your workspace"_ — when the app's
role requests the `AI` flag.

  ### Docs
- Documented `runAgent` and its `AI` permission-flag requirement in
_Skills & Agents_.
- Fixed outdated role-permission examples in _Roles & Permissions_
(`permissionFlags` → `permissionFlagUniversalIdentifiers`,
`PermissionFlag` → `SystemPermissionFlag`).

  ### Test plan
- [x] SDK unit tests (`run-agent.spec.ts`) — request shape, GraphQL/HTTP
error handling, missing env vars
- [x] `twenty-server`, `twenty-front`, `twenty-shared` typecheck + lint
- [ ] Manual: install an app granting the `AI` flag, call `runAgent()`
from a logic function, confirm the agent runs and credits are billed

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-06-04 16:18:27 +00:00
Raphaël BosiandGitHub 36b654bab3 Scaffold people data labs enrichment app (#21175)
# Scaffold People Data Labs enrichment app

Defines the data model for enriching **Person** and **Company** with
People Data
Labs data. **Scaffold only** — the enrichment logic (the "mapper")
follows
separately; see the package README.

## Included
- **Fields** on Person & Company (PDL base data set).
- **Enums as SELECT / MULTI_SELECT** validated against PDL canonical
files (v34.1).
- **Standard-field mapping**: no `pdl*` shadow where a standard field
exists.
- **Location → ADDRESS**; **relation** `pdlCurrentCompany` ↔
`pdlCurrentEmployees`.
- **Metadata**: `pdlId`, `pdlLikelihood`, `pdlEnrichmentStatus`,
`pdlLastEnrichedAt`, `pdlRawPayload`.
- Shared option constants + helper, indexes, and a view per object.
2026-06-04 15:54:38 +00:00
Raphaël BosiandGitHub 41d5d80a65 Migrate Company and Person standard fields in preparation for the enrichment app (#21171)
# Migrate Company and Person standard fields in preparation for the
enrichment app

## Why

Our standard `Person`/`Company` objects accumulated fields that aren't
generic to every
business, while missing a more universal revenue field that essentially
every CRM ships.
This PR makes the **Standard application** hold a tighter, more
universal set of fields,
and sets the stage for a follow-up PR that introduces a **People Data
Labs enrichment app**
to populate them.

## What changes

### Standard fields

**Demoted (Standard → Workspace Custom application)** — not generic
enough to ship as standard:

| Object  | Field                          | Type     |
| ------- | ------------------------------ | -------- |
| Company | annualRecurringRevenue (ARR)   | CURRENCY |
| Company | employees                      | NUMBER   |
| Company | idealCustomerProfile (ICP)     | BOOLEAN  |
| Company | xLink (X/Twitter)              | LINKS    |
| Person  | xLink (X/Twitter)              | LINKS    |
| Person  | city                           | TEXT     |

**Added (new generic Standard field)** — present in
Salesforce/HubSpot/Zoho, PDL-populatable:

| Object | Field | Type |
| ------- | ------------- |
-------------------------------------------------------- |
| Company | annualRevenue | CURRENCY (generic total revenue; replaces
the niche ARR) |

### Behavior by workspace

* **New workspaces:** demoted fields are gone; `annualRevenue` is
**active**.
* **Existing workspaces:** demoted fields are **preserved as active
custom fields, data intact**;
`annualRevenue` is created **inactive (opt-in)** with its column ready,
so a later activation
  is a metadata-only toggle.

### Upgrade commands (v2.9)

Three idempotent, per-workspace commands, run in timestamp order:

1. **`upgrade:2-9:move-demoted-standard-fields-to-custom-application`**
(1799000040000) —
re-owns the 6 demoted fields to the workspace custom application
(`isCustom = true`,
new `applicationId` + fresh `universalIdentifier`), keeping their data
and active state.
2. **`upgrade:2-9:rename-conflicting-custom-fields`** (1799000045000) —
if a workspace already
has a *custom* field named `annualRevenue`, renames it to
`annualRevenueCustom`
(data preserved via column rename) so the standard field can be added.
Skips non-custom matches.
3. **`upgrade:2-9:add-inactive-generic-standard-fields`**
(1799000050000) — creates
`Company.annualRevenue` on existing workspaces as inactive, guarded to
skip workspaces
   missing the target object or where the name is still taken.

**Failure model:** the workspace iterator isolates failures per
workspace (one workspace failing
never affects others); within a workspace the runner records per-command
status and resumes on the
next run, and every command is idempotent, so partial runs self-heal.

### Supporting changes

* **Field-option color palette:** widened the `TagColor` union
(`twenty-shared` `FieldMetadataOptions`
+ the field-metadata `options.input` DTO) from 10 colors to the full
theme palette, benefiting any
  future SELECT/MULTI_SELECT field.
* **Dev seeder:**
* The default "Annual Recurring Revenue" dashboard widget now points at
the generic
    `annualRevenue` field (renamed to "Annual Revenue").
* Removed the "Companies by Size (Stacked by City)" widget (relied on
the demoted `employees`).
* `employees` is dropped from company data seeds and re-added as a
**custom** field seed, so dev
workspaces still get an `employees` column matching the demoted
behavior.

### Cleanup

Front-end record types (`Company.ts`/`Person.ts`), the
`getDisplayNameFromParticipant` test mock,
metadata integration specs, the Zapier `crud_record` test, and the
regenerated
`get-standard-object-metadata-related-entity-ids` snapshot.

## ⚠️ Breaking change (intentional)

Removes standard fields `Company.annualRecurringRevenue`,
`Company.employees`,
`Company.idealCustomerProfile`, `Company.xLink`, `Person.xLink`, and
`Person.city` from the core
GraphQL schema (replaced by `Company.annualRevenue`).

This is why the breaking-changes check reports a large number of
removals — `graphql-inspector`
flags any removed object field plus its derived
aggregate/order-by/filter/update types.

**Mitigation:** the
`upgrade:2-9:move-demoted-standard-fields-to-custom-application` command
re-owns these fields as custom fields per workspace, preserving their
name and data, so existing
tenants keep working. New workspaces won't have them.
2026-06-04 15:54:04 +00:00
e0d42323af Add more control on http trigger (#21216)
add "new Response" utils to define response code or content type of http
route triggered logic function responses

follow up of https://github.com/twentyhq/twenty/pull/21214

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:34:10 +00:00
Abdullah.andGitHub d3a1781a59 Use serialize-javascript for JSON-LD serialization on twenty-website (#21223)
Our scanner flags the `dangerouslySetInnerHTML` in `JsonLd.tsx` as a
potential XSS sink. Since JSON-LD must be emitted as raw `<script
type="application/ld+json">` text (rendering it as a React child
HTML-entity-escapes it and corrupts the JSON, and the site is statically
generated so it must be in the SSG HTML for crawlers),
`dangerouslySetInnerHTML` is the correct, Next.js-documented approach
(the real fix is sanitizing the payload). This PR swaps our hand-rolled
`JSON.stringify().replace(/</g, ...)` for
[`serialize-javascript`](https://www.npmjs.com/package/serialize-javascript)
in `isJSON` mode, the maintained library [Next.js explicitly
recommends](https://nextjs.org/docs/app/guides/json-ld) for this, so the
script-unsafe characters are escaped by a vetted serializer rather than
custom code.
2026-06-04 14:38:18 +00:00
Thomas des FrancsandGitHub 70066cdcf4 Update Google Workspace and integration logo assets (#21185)
## Summary
- Replace the Gmail and Google Calendar assets with their May 2026 icon
refreshes.
- Update the shared Google, Google Meet, Microsoft Outlook, Microsoft
Calendar-provider, Docusign, Stripe, Tally, and Zapier logo assets.
- Regenerate matching website/front raster assets at their existing
dimensions.

## Preview

GitHub's file diff can render some tiny transparent SVG/WebP logo diffs
as nearly empty. This grid uses the final raster assets from the PR
branch; Stripe and Zapier use their official favicon marks.

| Logo | Preview |
| --- | --- |
| Gmail | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/gmail.webp"
width="48" height="48" alt="Gmail logo" /> |
| Google Calendar | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/calendar.webp"
width="48" height="48" alt="Google Calendar logo" /> |
| Google | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/google.webp"
width="48" height="48" alt="Google logo" /> |
| Google Meet | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/meet.webp"
width="48" height="48" alt="Google Meet logo" /> |
| Microsoft Outlook / Calendar | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/outlook.webp"
width="48" height="48" alt="Microsoft Outlook / Calendar logo" /> |
| Docusign | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/docusign.webp"
width="48" height="48" alt="Docusign logo" /> |
| Stripe | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/stripe.webp"
width="48" height="48" alt="Stripe logo" /> |
| Tally | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/tally.webp"
width="48" height="48" alt="Tally logo" /> |
| Zapier | <img
src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/zapier.webp"
width="48" height="48" alt="Zapier logo" /> |


## Notes
- Microsoft Calendar now uses the current Outlook/M365 icon, matching
the provider users connect for Microsoft calendar sync.
- Docusign keeps the compact Nexus mark for the small square logo slot,
regenerated from the current official Docusign lockup.
- Stripe now uses the official favicon mark from stripe.com.
- Zapier now uses the official square favicon mark from zapier.com.

## Sources
- Gmail 2026:
https://upload.wikimedia.org/wikipedia/commons/8/8f/Gmail_icon_%282026%29.svg
- Google Calendar 2026:
https://upload.wikimedia.org/wikipedia/commons/f/fa/Google_Calendar_icon_%282026%29.svg
- Google gradient G:
https://blog.google/company-news/inside-google/company-announcements/gradient-g-logo-design/
- Google Meet 2026:
https://commons.wikimedia.org/wiki/File:Google_Meet_icon_(2026).svg
- Microsoft 365 icon refresh:
https://techcommunity.microsoft.com/blog/microsoft365insiderblog/new-microsoft-365-icons-for-the-ai-era/4458674
- Docusign logo guidelines: https://brand.docusign.com/logo
- Stripe favicon:
https://images.stripeassets.com/fzn2n1nzq965/1hgcBNd12BfT9VLgbId7By/01d91920114b124fb4cf6d448f9f06eb/favicon.svg
- Tally press kit: https://tally.so/help/press-kit
- Zapier favicon: https://zapier.com/favicon.ico

## Validation
- Confirmed touched UI SVGs transform through SVGR successfully.
- Confirmed regenerated raster dimensions and alpha metadata with Sharp.
- Reviewed a generated contact sheet at 72px, 40px, and 16px.
- Ran `git diff --check`.
- Ran `packages/twenty-ui` Vite build with ARM Node v24.5.0:
`/Users/thomascolasdesfrancs/.nvm/versions/node/v24.5.0/bin/node
../../node_modules/vite/bin/vite.js build`.

Local note: `npx vite build` fails in `packages/twenty-ui` on this
machine because that directory resolves `/usr/local/bin/node` as x64
v23.5.0 while the Yarn install links Rollup's ARM optional package. The
direct ARM Node build above passed.
2026-06-04 14:19:49 +00:00
Abdullah becae12903 chore(website): downscale product-hero wheat bg and convert to webp
The source was a 4.2MB 6720x4480 JPEG used only as a WebGL halftone source.
Resize to 2048x1365 and encode as webp (q80) -> 170KB (~96% smaller), matching
the repo's webp convention.
2026-06-04 19:18:33 +05:00
Charles BochetandGitHub a7fed47932 fix(twenty-ui): prevent local visual diffs from polluting CI baselines (#21225)
## Summary

- **Username-prefix branches**: Local visual-diff builds now use
`charles/main` instead of `main` as the branch name, preventing local
runs from creating auto-approved reference builds that could overwrite
CI baselines.
- **Local merge-base computation**: Computes `ARGOS_REFERENCE_COMMIT`
via `git merge-base HEAD main` locally, so the Argos SDK skips `git
fetch origin <branch>` — fixing the "fatal: couldn't find remote ref"
error when running from non-pushed branches.
- **Pass `referenceCommit` to vitest plugin**: Ensures the locally
computed merge-base is forwarded to the Argos upload.

## Test plan

- [x] Verified local visual-diff works from `main` branch (branch
becomes `charles/main`, not auto-approved)
- [x] Verified local visual-diff works from a non-pushed branch
(`test/local-only-visual-diff` → build uploaded successfully)
2026-06-04 15:42:32 +02:00
Charles BochetandGitHub f4da7767f8 chore: remove Chromatic dependencies and configuration (#21221)
## Summary

- Remove `chromatic` and `@chromatic-com/storybook` devDependencies from
twenty-front
- Remove global `chromatic` Nx target from nx.json and twenty-front
project.json override
- Remove commented Chromatic Storybook addon from twenty-front
- Remove `CHROMATIC_PROJECT_TOKEN` from .env.example
- Update README to remove Chromatic sponsor reference (image was already
missing)
- Update stale Chromatic comment in toSpliced.ts

## Context

Visual regression testing has moved from Chromatic SaaS to self-hosted
Argos at `argos.twenty-internal.com`. These are dead references that are
no longer used by any CI workflow.

**Note:** Story `parameters.chromatic: { disableSnapshot: true }`
entries are intentionally kept — the Argos plugin reads them as a
fallback.

## Test plan

- Verify `yarn install` succeeds after dependency removal
- Verify no workflow references `chromatic` or `nx chromatic`
2026-06-04 13:15:23 +00:00
Charles BochetandGitHub badeaddd37 fix(ci): ensure ui-sb-test runs on push to main (#21222)
## Summary

- Add explicit `if: always() && needs.ui-sb-build.result == 'success'`
to `ui-sb-test` job

## Context

After merging #21217, the main-branch Argos baseline pipeline doesn't
work: `ui-sb-test` is silently skipped on push to main, so no
`argos-screenshots-twenty-ui` artifact is produced.

**Root cause:** `changed-files-check` is skipped on push events
(PR-only). `ui-sb-build` handles this with `if: always() && ...`, but
`ui-sb-test` has no explicit `if` — GitHub Actions propagates the skip
through the transitive dependency chain (`changed-files-check` →
`ui-sb-build` → `ui-sb-test`).

## Test plan

- Merge this PR and verify the next push to main produces the
`argos-screenshots-twenty-ui` artifact
- Verify `dispatch-main` successfully triggers ci-privileged with the
artifact
2026-06-04 15:11:38 +02:00
Charles BochetandGitHub 9042e8a542 feat(ci): Argos main baselines + local visual diff support (#21217)
## Summary

**CI: Main-branch Argos baselines**
- Run storybook build + screenshot capture on `push` to `main` in CI UI
workflow
- Add `dispatch-main` job in visual regression dispatch to forward
main-branch screenshots to ci-privileged
- Simplify `dispatch-pr` by inlining the artifact name and removing
unused `project` output

**Local visual diff support**
- Add `scripts/visual-diff.sh` for running Argos uploads locally via
tunnel
- Add `storybook:visual-diff` Nx target wrapping the script (depends on
`storybook:build`)
- Honor `STORYBOOK_URL` env in `vitest.config.ts` to reuse pre-served
static builds (mirrors twenty-front pattern)
- Support `ARGOS_BUILD_NAME`, `ARGOS_REFERENCE_BRANCH` env overrides in
vitest plugin config

## Context

Argos builds on PRs are all "Orphan" because there's no reference build
on `main` to compare against. The CI changes add the missing piece:
every merge to main now produces screenshots and uploads them to Argos
as reference builds.

The local visual diff script enables developers to run visual regression
checks from their machine against the self-hosted Argos instance via
`kubectl port-forward` (set up by the twenty-infra `argos-tunnel`
command).

## Related

- twentyhq/twenty-argos#1 (backend config for self-hosted HTTPS
redirect)
- twentyhq/twenty-infra#709 (argos-tunnel super CLI command +
self-hosted mode)

## Test plan

- [ ] Verify CI UI runs on next push to main and produces the
`argos-screenshots-twenty-ui` artifact
- [ ] Verify `dispatch-main` triggers and uploads screenshots to Argos
- [ ] Verify subsequent PR builds show diffs against the main baseline
instead of "Orphan"
- [ ] Run `ARGOS_TOKEN=<token> npx nx storybook:visual-diff twenty-ui`
locally with tunnel active
2026-06-04 14:55:08 +02:00
100b08e827 i18n - website translations (#21220)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-06-04 14:47:01 +02:00
437eed0862 fix(messaging): fix reply-quotation stripping that emptied email bodies (#21118)
some synced messages were stored with empty bodies, others with the
entire reply thread re-quoted, planer was stripping entirely quoted
forwards down to nothing and not trimming inline reply history at all

switched plaintext quote stripping to `email-reply-parser`, falling back
to the full text when it strips everything so forwards don't end up
blank. kept planer for the html path, and normalized body whitespac

---------

Co-authored-by: prastoin <paul@twenty.com>
2026-06-04 12:31:53 +00:00
Rashad KaranouhandGitHub 5a55021e26 feat(website): add /partners/apply standalone page (#21219)
## Summary

- Adds a standalone `/partners/apply` page — a shareable URL that opens
the partner application wizard full-page (no modal, no nav, no footer),
on a plain black background
- Adds a `slots` prop to `PartnerApplicationWizard` so it can render
outside a `Dialog.Root` context (Base UI), keeping the existing modal on
`/partners` completely untouched
- Surfaces logic function errors to the user: the API route now checks
the webhook response body for `ok: true`, so a silent backend failure no
longer shows a false success state

## Test plan

- [ ] `yarn jest --no-coverage` — 365/365 passing
- [ ] `npx oxlint -c .oxlintrc.json .` — 0 errors (1 pre-existing
warning unrelated to this PR)
- [ ] `npx oxfmt --check .` — clean
- [ ] `npx tsc --noEmit` — clean
- [ ] Visit `/partners/apply` — wizard loads full-page on black
background, no menu, no footer
- [ ] Complete the wizard and submit — redirects to `/partners/list`
- [ ] Visit `/partners` — "Become a partner" modal still opens normally
2026-06-04 12:30:26 +00:00
Raphaël BosiandGitHub 63435a7937 Twenty new ui README (#21186)
Generated a twenty new ui implementation plan README after the
discussion with @charlesBochet
2026-06-04 12:14:43 +00:00
6a2c948e84 chore: bump version to 2.10.0 (#21218)
## Summary

- Moves current version to previous versions array
- Sets TWENTY_CURRENT_VERSION to the new version
- Updates TWENTY_NEXT_VERSIONS with the next minor version
- Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same
version

## Checklist

- [ ] Verify version constants are correct
- [ ] Verify npm package versions match

Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com>
2026-06-04 14:14:18 +02:00
Charles BochetandGitHub b53f1832d8 feat(ci): simplify visual regression dispatch to twenty-ui only (#21215)
## Summary

- Only trigger visual regression on `CI UI` workflow (drop `CI Front`)
- Remove tarball re-packaging step — `ci-privileged` now downloads the
artifact directly via GitHub API
- Remove `mode`/`project` parameters from the dispatch payload
(hardcoded to twenty-ui in ci-privileged)
- Pass `run_id` of the triggering CI UI workflow so ci-privileged can
fetch the correct artifact

## Context

Part of the fast visual regression CI initiative. The `ci-privileged`
workflow has been simplified to only handle `twenty-ui` screenshots
uploaded directly to Argos.

## Test plan

- [x] Full E2E verified on production: screenshots → Argos build → diff
results → PR comment
2026-06-04 13:49:44 +02:00
Paul RastoinandGitHub 3d49642d12 [AUDIT] Run knip over twenty-server (#21159)
# Introduction
Run [knip](https://knip.dev/) over twenty-server
Used config:
```json
{
  "$schema": "https://unpkg.com/knip@5/schema.json",
  "workspaces": {
    "packages/twenty-server": {
      "entry": [
        "src/main.ts",
        "src/command/command.ts",
        "src/queue-worker/queue-worker.ts",
        "src/database/scripts/setup-db.ts",
        "src/database/scripts/truncate-db.ts",
        "src/database/clickHouse/migrations/run-migrations.ts",
        "src/database/clickHouse/seeds/run-seeds.ts",
        "src/instrument.ts",
        "lingui.config.ts",
        "test/integration/graphql/codegen/index.ts",
        "test/integration/utils/setup-test.ts",
        "test/integration/utils/teardown-test.ts",
        "scripts/**/*.ts",
        "**/*.spec.ts",
        "**/*.integration-spec.ts"
      ],
      "project": ["src/**/*.ts", "test/**/*.ts", "scripts/**/*.ts"],
      "ignore": [
        "src/database/typeorm/**/migrations/**",
        "src/database/typeorm/**/*.entity.ts",
        "**/*.workspace-entity.ts",
        "**/logic-function-resource/constants/seed-project/**"
      ],
      "ignoreDependencies": ["@types/psl", "@types/aws-lambda"],
      "ignoreBinaries": ["nest", "lingui", "typeorm"]
    }
  }
}
```
2026-06-04 10:05:22 +00:00
Abdullah.andGitHub 86cad7aee6 Merge branch 'main' into website-product-hero 2026-06-04 14:49:54 +05:00
martmullandGitHub 4ad8d8e98e Set 200 code for post requests (#21214)
as title, nestJS use to set 201 for post requests but some services
(like google) requests 200 response code

See
https://discord.com/channels/1130383047699738754/1511054250971758642/1511785364027609099
for context
2026-06-04 09:14:51 +00:00
nitinandGitHub 475cd9e7fe fix(upgrade): resequence workflow step logs command (#21213) 2026-06-04 08:27:43 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
f0be78e629 chore(deps-dev): bump prettier from 3.4.2 to 3.8.3 (#21205)
Bumps [prettier](https://github.com/prettier/prettier) from 3.4.2 to
3.8.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>3.8.3</h2>
<ul>
<li>SCSS: Prevent trailing comma in <code>if()</code> function (<a
href="https://redirect.github.com/prettier/prettier/pull/18471">prettier/prettier#18471</a>
by <a href="https://github.com/kovsu"><code>@​kovsu</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.8.3/CHANGELOG.md#383">Changelog</a></p>
<h2>3.8.2</h2>
<ul>
<li>Support Angular v21.2</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#382">Changelog</a></p>
<h2>3.8.1</h2>
<ul>
<li>Include available <code>printers</code> in plugin type declarations
(<a
href="https://redirect.github.com/prettier/prettier/pull/18706">#18706</a>
by <a href="https://github.com/porada"><code>@​porada</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#381">Changelog</a></p>
<h2>3.8.0</h2>
<ul>
<li>Support Angular v21.1</li>
</ul>
<p><a
href="https://github.com/prettier/prettier/compare/3.7.4...3.8.0">diff</a></p>
<p>🔗 <a href="https://prettier.io/blog/2026/01/14/3.8.0">Release note
&quot;Prettier 3.8: Support for Angular v21.1&quot;</a></p>
<h2>3.7.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix comment in union type gets duplicated by <a
href="https://github.com/fisker"><code>@​fisker</code></a> in <a
href="https://redirect.github.com/prettier/prettier/pull/18393">prettier/prettier#18393</a></li>
<li>Fix unstable comment print in union type by <a
href="https://github.com/fisker"><code>@​fisker</code></a> in <a
href="https://redirect.github.com/prettier/prettier/pull/18395">prettier/prettier#18395</a></li>
<li>Avoid quote around LWC interpolations by <a
href="https://github.com/kovsu"><code>@​kovsu</code></a> in <a
href="https://redirect.github.com/prettier/prettier/pull/18383">prettier/prettier#18383</a></li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#374">Changelog</a></p>
<h2>3.7.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix <code>prettier.getFileInfo()</code> change that breaks VSCode
extension by <a
href="https://github.com/fisker"><code>@​fisker</code></a> in <a
href="https://redirect.github.com/prettier/prettier/pull/18375">prettier/prettier#18375</a></li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#373">Changelog</a></p>
<h2>3.7.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix string print when switching quotes by <a
href="https://github.com/fisker"><code>@​fisker</code></a> in <a
href="https://redirect.github.com/prettier/prettier/pull/18351">prettier/prettier#18351</a></li>
<li>Preserve quote for embedded HTML attribute values by <a
href="https://github.com/kovsu"><code>@​kovsu</code></a> in <a
href="https://redirect.github.com/prettier/prettier/pull/18352">prettier/prettier#18352</a></li>
<li>Fix comment in empty type literal by <a
href="https://github.com/fisker"><code>@​fisker</code></a> in <a
href="https://redirect.github.com/prettier/prettier/pull/18364">prettier/prettier#18364</a></li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#372">Changelog</a></p>
<h2>3.7.1</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>3.8.3</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.8.2...3.8.3">diff</a></p>
<h4>SCSS: Prevent trailing comma in <code>if()</code> function (<a
href="https://redirect.github.com/prettier/prettier/pull/18471">#18471</a>
by <a href="https://github.com/kovsu"><code>@​kovsu</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="scss"><code>// Input
$value: if(sass(false): 1; else: -1);
<p>// Prettier 3.8.2
$value: if(
sass(false): 1; else: -1,
);</p>
<p>// Prettier 3.8.3
$value: if(sass(false): 1; else: -1);
</code></pre></p>
<h1>3.8.2</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.8.1...3.8.2">diff</a></p>
<h4>Angular: Support Angular v21.2 (<a
href="https://redirect.github.com/prettier/prettier/pull/18722">#18722</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19034">#19034</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</h4>
<p>Exhaustive typechecking with <code>@default never;</code></p>
<!-- raw HTML omitted -->
<pre lang="html"><code>&lt;!-- Input --&gt;
@switch (foo) {
  @case (1) {}
  @default never;
}
<p>&lt;!-- Prettier 3.8.1 --&gt;
SyntaxError: Incomplete block &quot;default never&quot;. If you meant to
write the @ character, you should use the &quot;&amp;<a
href="https://redirect.github.com/prettier/prettier/issues/64">#64</a>;&quot;
HTML entity instead. (3:3)</p>
<p>&lt;!-- Prettier 3.8.2 --&gt;
<a href="https://github.com/switch"><code>@​switch</code></a> (foo) {
<a href="https://github.com/case"><code>@​case</code></a> (1) {}
<a href="https://github.com/default"><code>@​default</code></a> never;
}
</code></pre></p>
<p><code>arrow function</code> and <code>instanceof</code>
expressions.</p>
<!-- raw HTML omitted -->
<pre lang="html"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/prettier/prettier/commit/d7108a79ec745c04292aabf22c4c1adbd690b191"><code>d7108a7</code></a>
Release 3.8.3</li>
<li><a
href="https://github.com/prettier/prettier/commit/177f90898170d363ef64fde663e4d13170688bfe"><code>177f908</code></a>
Prevent trailing comma in SCSS <code>if()</code> function (<a
href="https://redirect.github.com/prettier/prettier/issues/18471">#18471</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/1cd40668c3d6f2f4cf9d87bbc9096d92361b2606"><code>1cd4066</code></a>
Release <code>@​prettier/plugin-oxc</code><a
href="https://github.com/0"><code>@​0</code></a>.1.4</li>
<li><a
href="https://github.com/prettier/prettier/commit/a8700e245038cd8cc0cf28ef06ffedbcb3fc2dfc"><code>a8700e2</code></a>
Update oxc-parser to v0.125.0</li>
<li><a
href="https://github.com/prettier/prettier/commit/752157c78eca6f0a30e5d5cb513b682c5ecfa01e"><code>752157c</code></a>
Fix tests</li>
<li><a
href="https://github.com/prettier/prettier/commit/053fd418e180b12fa2014260212fae831f5fc5ec"><code>053fd41</code></a>
Bump Prettier dependency to 3.8.2</li>
<li><a
href="https://github.com/prettier/prettier/commit/904c6365ec46726fd0e21021c52ae934b7e5abc6"><code>904c636</code></a>
Clean changelog_unreleased</li>
<li><a
href="https://github.com/prettier/prettier/commit/dc1f7fcc508d116cbf1644d69a1f0eb93e40d4a4"><code>dc1f7fc</code></a>
Update dependents count</li>
<li><a
href="https://github.com/prettier/prettier/commit/b31557cf331a02acf83e7e29d1001b070189a0d9"><code>b31557c</code></a>
Release 3.8.2</li>
<li><a
href="https://github.com/prettier/prettier/commit/96bbaeda0525bf758e464aed2f939d739a85c315"><code>96bbaed</code></a>
Support Angular v21.2 (<a
href="https://redirect.github.com/prettier/prettier/issues/18722">#18722</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/prettier/prettier/compare/3.4.2...3.8.3">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for prettier since your current version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=prettier&package-manager=npm_and_yarn&previous-version=3.4.2&new-version=3.8.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-04 09:45:41 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fe5337b7d0 chore(deps-dev): bump @types/passport-microsoft from 2.1.0 to 2.1.1 (#21204)
Bumps
[@types/passport-microsoft](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/passport-microsoft)
from 2.1.0 to 2.1.1.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/passport-microsoft">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/passport-microsoft&package-manager=npm_and_yarn&previous-version=2.1.0&new-version=2.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-04 09:45:19 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
f50e471385 chore(deps): bump @mantine/hooks from 8.3.15 to 8.3.18 (#21203)
Bumps
[@mantine/hooks](https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks)
from 8.3.15 to 8.3.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/mantinedev/mantine/releases">@​mantine/hooks's
releases</a>.</em></p>
<blockquote>
<h2>8.3.18</h2>
<p>This is the last 8.x release. You are welcome to test 9.0 alpha
version and provide feedback before its release on March 31 – <a
href="https://alpha.mantine.dev/changelog/9-0-0/">https://alpha.mantine.dev/changelog/9-0-0/</a></p>
<ul>
<li><code>[@mantine/core]</code> PasswordInput: Fix styles api props not
resolving correctly in theme (<a
href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8716">#8716</a>)</li>
</ul>
<h2>8.3.17</h2>
<h2>Changes</h2>
<ul>
<li><code>[@mantine/core]</code> Stepper: Fix Google Translate
compatibility issues (<a
href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8744">#8744</a>)</li>
<li><code>[@mantine/hooks]</code> use-list-state: Add memoization to all
handlers (<a
href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8739">#8739</a>)</li>
</ul>
<h2>8.3.16</h2>
<h2>What's Changed</h2>
<ul>
<li><code>[@mantine/modals]</code> Fix <code>onClose</code> being called
multiple times (<a
href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8727">#8727</a>)</li>
<li><code>[@mantine/core]</code> Tooltip: Fix component not throwing
erro when used with string (<a
href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8694">#8694</a>)</li>
<li><code>[@mantine/core]</code> NumberInput: Fix incorrect decimal
separator parsing in <code>onPaste</code></li>
<li><code>[@mantine/core]</code> AppShell: Fix
<code>layout=&quot;alt&quot;</code> not working with
<code>mode=&quot;static&quot;</code></li>
<li><code>[@mantine/stotlight]</code> Fix actions list being rendered
when nothing found message was not set (<a
href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8592">#8592</a>)</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/mantinedev/mantine/compare/8.3.15...8.3.16">https://github.com/mantinedev/mantine/compare/8.3.15...8.3.16</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/mantinedev/mantine/commit/530249feb498d74d5ea849d2984c86efd072f38c"><code>530249f</code></a>
[release] Version: 8.3.18</li>
<li><a
href="https://github.com/mantinedev/mantine/commit/bac61d6fc21be84bd80d1d9232a605c05692ae75"><code>bac61d6</code></a>
[release] Version: 8.3.17</li>
<li><a
href="https://github.com/mantinedev/mantine/commit/6b3fdee137584aece43b88b62d8c207a58c35295"><code>6b3fdee</code></a>
[refactor] Fix formatting</li>
<li><a
href="https://github.com/mantinedev/mantine/commit/c048f996cc1a8287bd9eaba1bb59bc6637316b90"><code>c048f99</code></a>
[<code>@​mantine/hooks</code>] use-list-state: Add memoization to all
handlers (<a
href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8739">#8739</a>)</li>
<li><a
href="https://github.com/mantinedev/mantine/commit/dbb8732ca3350259e0cf7b2536d0bcc885b1b587"><code>dbb8732</code></a>
[release] Version: 8.3.16</li>
<li>See full diff in <a
href="https://github.com/mantinedev/mantine/commits/8.3.18/packages/@mantine/hooks">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@mantine/hooks&package-manager=npm_and_yarn&previous-version=8.3.15&new-version=8.3.18)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-04 09:45:10 +02:00
Félix MalfaitandGitHub a3a44c8315 fix(front): settings skeleton, app-detail header & empty favorites (#21209)
Three small post-redesign UI fixes. Each is an independent commit, so
they can be split into separate PRs if preferred.

## 1. Settings loading skeleton — match the rounded-card layout

The redesign (#21131) moved settings chrome into a rounded card
(`SettingsPageLayout`: bordered header with breadcrumb + centered title,
optional secondary bar, 760px body), but `SettingsSkeletonLoader` still
rendered the old flat `PageHeader` + `PageBody` — so pages painted as a
full-width flat bar then snapped into the card.

- `SettingsSkeletonLoader` now reproduces the card and **reuses the real
`SettingsPageHeader` + `SettingsPageContainer`**, so the frame aligns by
construction; the card CSS is replicated (not `SettingsPageLayout`) to
avoid the layout's side effects (hotkeys, side panel, info banner).
- It's **composed with `SettingsSectionSkeletonLoader`** so the loading
body is identical whether or not chrome is present. Rule: no chrome on
screen yet → full-page skeleton; chrome already on screen → body-only
`SettingsSectionSkeletonLoader` (the admin Enterprise tab now uses it,
matching its sibling tabs). A short comment on each component documents
this.

## 2. Application detail header — pass a plain title

`SettingsApplicationDetails` / `SettingsAvailableApplicationDetails`
passed a custom `SettingsApplicationDetailTitle` (avatar + name +
multi-line description, fixed width) into `SettingsPageLayout`'s
**centered single-line title slot**, which broke the header. They now
pass the app's display name like every other page. The available-app
"unlisted" notice moves into the body as a reusable `InlineBanner`; the
now-unused `SettingsApplicationDetailTitle` is removed.

## 3. Navigation — hide Favorites when empty

Always rendering the Favorites section (#21087) left a stray "Favorites"
title above Workspace for users with no favorites. It now renders only
when at least one favorite exists (redundant per-child guards dropped).
Note: the "+ add favorite" entry point therefore appears once you have
≥1 favorite; the first favorite is created from a record/view as before.

## Verification
- `nx typecheck twenty-front`  · `oxlint` + `oxfmt --check` on changed
files 
- i18n catalogs intentionally untouched — handled by the repo's separate
i18n pipeline.
2026-06-04 09:32:36 +02:00
e99116b0a5 chore: sync AI model catalog from models.dev (#21212)
Automated daily sync of `ai-providers.json` from
[models.dev](https://models.dev).

This PR updates pricing, context windows, and model availability based
on the latest data.
New models meeting inclusion criteria (tool calling, pricing data,
context limits) are added automatically.
Deprecated models are detected based on cost-efficiency within the same
model family.

**Please review before merging** — verify no critical models were
incorrectly deprecated.

Co-authored-by: FelixMalfait <6399865+FelixMalfait@users.noreply.github.com>
2026-06-04 09:31:01 +02:00
Abdullah 81b2155e7d Render product hero as stacked sections below md
The sticky scroll-morph relied on 200vh/100dvh/innerHeight which disagree on
mobile (toolbar-driven viewport), causing jumpy scroll and a long dead-scroll
tail, and the flex:1 visual reserved full-viewport height under a short
aspect-ratio preview, leaving an empty band. Below md, drop the morph and
render the intro and AI as two plain content-sized sections.
2026-06-03 17:58:15 +05:00
Abdullah 5c6701e37a Refine product-hero cursor handoffs and simplify tour state
- Wait for the previous cursor to return home before the next moves on the
  Anthropic-row and Notes-tab handoffs (insert home-hold beats)
- Make the loop seam return to the settle beat so Cara lands home before
  Alice starts, and give her cross-window return room (cap 960->1000, longer
  Companies-rail move + seam beat) instead of the old slow-glide override
- Drop CURSOR_COUNT: the hook now returns the active cursor's state and
  ProductVisual derives per-cursor state from HERO_CURSORS; idle cursors
  default to home via an optional target prop
2026-06-03 17:25:39 +05:00
Abdullah 1e196e410d feat(website): float product-hero multiplayer cursors in the hero layer
Portal the cursors out of the clipped visual into the intro hero layer so
they rest in the page whitespace (and still glide onto in-window targets,
which the layer contains). Reposition the three home spots accordingly.
2026-06-03 16:37:49 +05:00
Abdullah 729b8269a0 refactor(website): strip inert machinery from product-hero halftone
Remove the HomeHero-derived zoom/footprint-scale system, image pixel
offsets, edgeFade/solidness, and applyToDarkAreas from the product
background halftone -- all were no-ops at the fixed settings. Render is
unchanged; the shader is now just a cover-fit image pass + halftone pass.
2026-06-03 16:20:06 +05:00
Abdullah 15795191d4 chore(website): rename product-hero wheat asset to home-background-wheat 2026-06-03 16:13:17 +05:00
Abdullah 632bf9609f feat(website): wheat-field halftone background for product hero
Adopt the halftone-studio wheat-field look in the existing typed,
visual-runtime-based ProductBackgroundHalftone instead of the standalone
studio export: cover-fit image, denser dash settings (tile 8, power 0.1,
width 0.52, contrast 0.95), and per-layer dash color (purple on the white
intro, white on the dark AI section). Removes the orphaned ai-bg-1 asset.
2026-06-03 16:09:23 +05:00
Abdullah 05eea18241 feat(website): image-driven halftone background for product hero
Replace the procedural product-hero background with an image-driven
two-pass halftone (HomeHero-style), full-bleed behind the visual,
sampling a mapped landscape image.
2026-06-03 00:20:36 +05:00
Abdullah bd86e3f3f1 refactor(website): drop dead code in product-hero autoplay
Remove the unused preambleComplete return and two unnecessary useMemos
(fullTextVisibleLength, scenePhase) that memoized trivial pure computations.
2026-06-02 20:01:43 +05:00
Abdullah 33480c6699 feat(website): multiplayer cursors for the product-hero AI demo
- Render three labelled cursors (Alice/Ben/Cara) that frame the visual at
  its edges and take turns clicking through the tour
- Give every view (Companies, the three record tabs, People, Notes) an
  equal ~1700ms on screen
- Time cursor glides from pixel distance anchored to a calm baseline so
  short and long moves read as synchronized, and skip sub-threshold
  re-measures so an in-flight glide is never snapped
- Slow Alice's approach to the Anthropic row so she lands as Cara finishes
  her cross-window return home
2026-06-02 19:58:06 +05:00
Abdullah ac5eb7cc5e feat(website): tighten product-hero stack and refine collapse/spread timing
- Tighten the resting stack (offsets [0,4,8,12], subtler per-card scale)
- Snappy vertical collapse (0.62-0.66) handing straight off to the
  horizontal spread with no overlap or waiting gap
- Slow, eased horizontal spread (0.66-0.93) landing before the selector
  reveal; move the appear entrance and deck shift to match the tighter stack
2026-06-02 18:23:54 +05:00
Abdullah e3839c364f feat(website): split product-hero prompt buttons to the sides earlier
Move the tab stack align/spread windows earlier in the morph so the
buttons fan out to the sides sooner (align 0.50-0.66, spread 0.64-0.84).
2026-06-02 18:01:22 +05:00
Abdullah 764421d8ff feat(website): use semantic tabler icons for product-hero prompt chips
Replace the generic eye/check/lightbulb/code glyphs with icons that match
each prompt: kanban board, checklist, bar chart, and workflow hierarchy.
Added as new informative-icon registry keys so existing usages are unchanged.
2026-06-02 17:53:19 +05:00
Abdullah 231a4715df fix(website): product-hero skeleton polish and earlier view reveal
- Reveal skeleton-loader views (kanban, table, dashboard, workflow) as
  soon as the answer starts streaming instead of after it completes
- Neutralize the skeleton shimmer to twenty-front's grey palette
  (#f1f1f1 base) to remove the cool/blue cast
- Widen entity chip horizontal padding to 3px 6px to match the vertical
2026-06-02 17:47:29 +05:00
Abdullah ea4f27caca feat(website): match product-hero AI panel to twenty-front
Align the product-hero AI chat panel with twenty-front's real chat:
- Type scale: 13px title/messages/chips, 12px thinking-step labels
- Thinking rows use twenty's primitives — orbit loader (active), IconCpu
  (done), light/tertiary icon tones, plain (non-shimmer) labels
- Collapse finished steps into an "N steps" summary, mirroring
  ThinkingStepsDisplay's expand/collapse logic
- Stream the assistant response as separate paragraphs (string[] so each
  stays an independent translation unit) with twenty's 8px paragraph
  spacing and 1.5 line-height
2026-06-02 17:28:49 +05:00
Abdullah 077d5ee500 refactor(website): share one fade keyframe across workflow node content
- Replace the three duplicate workflowNode*Appear keyframes with a single nodeContentAppear css fragment applied via className
- Keeps the keyframe and its animation co-located so Linaria scopes them together (single source of truth for timing)
2026-06-01 20:03:05 +05:00
Abdullah d17e90b931 fix(website): remove the page flash when the product hero tour clicks the sidebar
- Set each rail click's destination pageItemId during the click phase so selectPageItem applies before the reveal
- Prevents the record -> stale Companies -> People flash (and equivalent stale frames on the other rail clicks)
2026-06-01 19:54:45 +05:00
Abdullah 802b1468cf fix(website): shorten the Notes/Calendar dwell in the product hero record tour
- Cut the Notes and Calendar tab dwell ~1/3 so the cursor lingers less and each tab is in view briefly
2026-06-01 19:46:36 +05:00
Abdullah 6e4a2ec185 refactor(website): address product hero review feedback
- Collapse the duplicate viewbar wrappers into a single ViewbarBar
- Style the workflow canvas via a data-workflow-canvas hook instead of an aria-label substring + positional selector
- Use the TABLE_PAGE_COLORS.text token for the checkbox border instead of a hardcoded hex
- Extract shared rail-item styles into a css fragment
- Match the workflow skeleton icon radius to the real node icon
2026-06-01 19:46:35 +05:00
Abdullah b346237263 feat(website): reset the AI section to the first tab when the hero returns to the top
- Reset activeTab to 0 once morphProgress falls back to 0 (fully scrolled back to the intro)
- Partial scroll-backs keep the selected tab
2026-06-01 17:29:31 +05:00
Abdullah e49dcc3183 feat(website): restart the product hero intro tour when scrolling back from the AI section
- Gate the collaborative cursor tour on the intro being the dominant view (morphProgress < 0.5)
- Reset the tour to its first phase when disabled so re-entering the intro replays from the start
2026-06-01 17:09:31 +05:00
Abdullah 8010e28b24 fix(website): coherent AI-section counts and clean ARR chart reveal
- Hide the pipeline/tasks header count while generating so it reads as built by AI, not pre-existing
- Show 10 tasks (the count the AI claims) instead of base+new
- Fade the ARR line/area in as a complete line instead of a stroke-draw that flashed a partial segment
2026-06-01 16:57:26 +05:00
Abdullah 5312a2fd56 feat(website): drive the product hero record tabs with the cursor
- Externally control the record's active tab (RecordPageDefinition.activeTabLabel); disable self-advance when controlled
- Cursor clicks Timeline -> Notes -> Calendar before navigating the sidebar, so tabs no longer flip on their own
- Add a tab cursor target (data-record-tab) and tune rail/tab landing offsets and the row->tab glide pacing
2026-06-01 16:30:22 +05:00
Abdullah a12a060985 feat(website): turn the product hero intro into a guided multi-page tour
- Replace the single-record tab loop with a looping cursor tour: Companies -> Anthropic record -> People -> Notes
- Keep the cursor hidden while the record plays its tabs to Calendar, then navigate the sidebar rail
- Generalize the hero cursor to target table rows and rail items; add data-rail-item-id to rail items
- Deliberately avoid the AI section's surfaces (pipeline/tasks/dashboard/workflow)
2026-06-01 16:18:27 +05:00
Abdullah c5ffdd13a9 chore(website): remove dead OpenAI/Sam Altman demo data from product hero
- Delete the unused NEW_COMPANY_ROW/NEW_PERSON_ROW lead-creation rows and their resolveDisplayPage branch
- Clear the intro scene's unused AI response copy and prune the now-dead scene phases
- Replace Sam Altman (a competitor CEO) in Anthropic's QBR with a generic teammate
2026-06-01 15:44:06 +05:00
Abdullah 3fcfb39e7d fix(website): align pipeline board stages with copy and soften halftone hover
- Rename kanban lanes to New/Screening/Meeting/Proposal/Customer to match the AI response copy, the dashboard's deals-by-stage chart, and Twenty's default opportunity stages
- Reduce the halftone hover lift intensity and make it a tunable constant
2026-06-01 15:29:10 +05:00
Abdullah 80e0d6092e feat(website): darker, dashed hero halftone tone and pattern
- Add a solidness control to the product halftone; intro renders darker, edge-to-edge dashes while the AI section keeps its faded look
- Cap dash half-length so dense cells stay dashed instead of merging into solid lines (both heroes)
2026-06-01 15:15:53 +05:00
Abdullah 41baeefcae feat(website): stage the product hero workflow build animation
- Suppress edges, branch labels and plus node during generation so it no longer looks pre-built
- Draw edges in sequentially, then ease in ports, connector, labels and the add-node as a finale
- Fade in node content; drive edge stagger via inline animationDelay to avoid leaking a DOM prop
2026-06-01 06:58:38 +05:00
Abdullah e261f1268e feat(website): reuse AI halftone for product hero intro, scoped to the visual
- Drop the bespoke intro halftone; render the AI section's halftone tinted with the intro's blue
- Scope both hero halftones inside the visual wrapper so they no longer sit behind the CTA/tab buttons
- Remove the now-orphaned ProductIntroHalftone, its hook, and the skyline texture
2026-06-01 06:44:40 +05:00
Abdullah a42f91e494 feat(website): flow the hero color wipe up into the product menu
- Span the dark wipe across the full viewport so it rises continuously through the nav
- Make the menu transparent only while the black sweeps through it, solid (dark) once complete, and white again on exit
- Shorten AI hero tab labels to fit without ellipsis while keeping full prompts
2026-06-01 06:32:50 +05:00
Abdullah 108d850000 feat(website): coherent skeleton loading and real charts across product hero AI scenes
- Stream the AI answer first, reveal the CRM artifact as a finale
- Restructure the 4 AI prompts into build pillars (board, tasks, dashboard, workflow)
- Render real animated SVG charts for the dashboard, matched to twenty-front step-8 palette
- Add a unified `generating` skeleton state across table, kanban, workflow and dashboard surfaces
- Share PreviewSkeleton primitives with a single shimmer keyframe
2026-06-01 05:26:08 +05:00
Abdullah e346b9f505 feat(website): add agentic thinking + tool steps to product hero AI panel 2026-06-01 03:00:59 +05:00
Abdullah cd1c188fb1 feat(website): cycle record tabs with twenty-front parity and post-tour clicking 2026-06-01 02:12:30 +05:00
Abdullah 27b2f0cab7 feat(website): render full-fidelity timeline on product hero record page 2026-06-01 00:35:37 +05:00
Abdullah 45aa0898f2 feat(website): replace product hero intro AI panel with collaborative cursor demo 2026-05-31 23:53:00 +05:00
Abdullah 0ff7b6b365 fix(website): start product hero morph on first scroll 2026-05-31 22:46:08 +05:00
Abdullah 2a77c4c7f5 chore(website): remove orphaned image assets (zero references) 2026-05-31 21:40:01 +05:00
Abdullah e5be4e09e5 refactor(website): drop dead guard on required stepVisuals prop 2026-05-31 21:35:56 +05:00
Abdullah 0759333e8f refactor(twenty-website): type the social/client icon registries + catalog widths
Continue Phase 0 across the icon/identifier registries:
- SOCIAL_ICONS and CLIENT_ICONS now use 'satisfies' and export their key unions
  (SocialIconKey, ClientIconKey).
- Type the data fields against them: MenuSocialLinkType.icon, HeadingCardType.icon,
  and CaseStudy/CaseStudyCatalog 'clientIcon' (was string) — all compile-checked.
- CATALOG_LOGO_WIDTHS becomes a total Record<ClientIconKey, number>; its '?? 140'
  defaults are now dead (a new client is a compile error, not a silent default).
- Remove the now-dead guards: 'if (!IconComponent) return null' in Menu Social +
  Drawer, and the 'IconComponent ? : null' in HelpedCard. Footer's social icon,
  previously unguarded over a lying Record<string>, is now type-safe.

typecheck/lint/build green; all existing keys were valid.
2026-05-31 20:15:30 +05:00
Abdullah 7d3a5802be refactor(twenty-website): type the INFORMATIVE_ICONS registry + its keys
Phase 0 (type-tightening), first registry. INFORMATIVE_ICONS was annotated
Record<string, …>, so every icon key compiled unchecked and every lookup was
typed as always-defined while actually being maybe-undefined at runtime — which
is why each call site carried an 'Icon ? … : null' guard.

- Type the registry with 'satisfies' so it self-describes its key union, and
  export InformativeIconKey = keyof typeof INFORMATIVE_ICONS.
- Replace 'icon: string' with InformativeIconKey in TabType, the product-stepper
  step types, and FeatureBullet — icon keys in data are now compile-checked.
- Drop the now-redundant 'as keyof' cast and the three dead 'Icon ? : null'
  guards (the lookup is provably defined for a valid key).

typecheck/lint/build green; every existing icon value was already valid.
2026-05-31 20:00:10 +05:00
Abdullah 1522704387 style(twenty-website): format product-hero files to oxfmt
The product-hero branch's files predated main's oxfmt config and failed
oxfmt --check after the merge. Apply oxfmt across them (AppPreview, ProductVisual,
the app-preview data) — formatting only, no behavior change. Kept as its own
commit so the structural cleanup stays reviewable.
2026-05-31 19:22:21 +05:00
Abdullah 623847251f refactor(twenty-website): tidy product-hero merge artifacts
Post-merge structural cleanup found by auditing the auto-merged files:
- Remove hero-scroll-colors.ts — ~200 lines of scroll/color helpers that were
  already dead on the branch (zero importers, pre-merge).
- Lift app-preview.data.ts out of the app/(home) route folder into the
  AppPreview section that owns it, and export APP_PREVIEW_DATA from the section
  barrel. Breaks the home->product cross-route data coupling; home, product
  hero, and product demo now all import it from @/sections/AppPreview. The data
  file's type import points at ./types to avoid a barrel cycle.

typecheck (tsc + tsgo), build, boundaries, section-shape, oxlint all pass.
2026-05-31 19:20:18 +05:00
Abdullah d724a587f7 refactor(twenty-website): rework product hero onto post-refactor structure
Reconcile the product-hero branch with main's restructure (page-local blocks,
flattened Menu):
- ProductHeroMenuSync: rebuild against the flat <Menu> (the refactor removed the
  compound Menu.Root/.Logo/.Nav/.Cta API). It now renders <Menu> with the
  scroll-derived backgroundColor + scheme; the morph-progress context the hero
  feeds is unchanged.
- product/page.tsx: wrap the page-local <ProductHero> in <ProductHeroMenuSync>
  (which now owns the menu) instead of rendering a static <Menu>.
- ProductHero: re-apply the branch's refined hero copy and restore the
  'Talk to us' secondary CTA (introSecondaryCta), as <Trans> units.
- Fix two pre-existing lint errors the merge surfaced (unused theme import;
  duplicated SidebarDesktopItem import).
2026-05-31 18:39:37 +05:00
Abdullah 1c41422177 Merge branch 'main' into website-product-hero
# Conflicts:
#	packages/twenty-website/src/app/[locale]/product/page.tsx
#	packages/twenty-website/src/sections/Demo/components/Preview.tsx
2026-05-31 18:21:03 +05:00
Abdullah b24acd0c98 fix: row gap between subtitle and buttons 2026-05-26 19:56:53 +05:00
Abdullah e0056ff197 fix: button stacking 2026-05-26 01:13:20 +05:00
Abdullah edca145544 feat(website): refine product hero ai demos and app preview navigation 2026-05-26 00:42:53 +05:00
Abdullah 635157e7d0 feat(website): refine product hero ai transition and preview fidelity 2026-05-25 22:36:47 +05:00
Abdullah 504494ebfa feat(website): refine app preview fidelity across product hero scenes 2026-05-25 20:04:33 +05:00
Abdullah f04958469e feat(website): add symmetric skyline halftone to product hero intro
Adds a halftone background effect to the product hero intro section using
a symmetric skyline image with edge-detected outlines, matching the Home
Hero's proven halftone architecture and parameters.
2026-05-24 12:48:01 +05:00
Abdullah 776ce25617 feat(website): update product hero intro background image 2026-05-23 21:05:02 +05:00
Abdullah 06a2b2dc04 feat(website): add procedural halftone background and fix hydration errors
- Replace static background image with procedural WebGL halftone glow on AI layer
- Refactor hero to clip-path wipe transition with two stacked layers
- Fix hydration mismatch by removing useId() from EditIcon and HeroVisualScroll
- Add ProductBackgroundHalftone component with mouse-follow hover interaction
2026-05-23 20:37:48 +05:00
Abdullah 431d487b6a feat(website): smooth scroll-driven hero morph with synced nav
Replace the binary phase-switch hero with a continuous scroll-driven
morph: background/nav interpolate smoothly while text swaps at the
threshold. Nav reverts to light only after the hero leaves the viewport.
2026-05-22 15:18:32 +05:00
Abdullah 2e081575fe feat(website): add sliding hero tabs and improve mobile nav color sync
Introduce a sliding tab indicator for the product AI hero and align the
sticky nav transition on mobile with the intro/AI boundary using measured
nav height, earlier lead offset, and blur-free solid backgrounds.
2026-05-22 15:18:32 +05:00
Abdullah 90d09fe0a5 fix(website): polish product hero opacity sync and hydration
Align dark overlay and nav opacity with the AI panel when fully in view,
use stable tab ids and remove Edit icon clipPath useId to fix SSR mismatches,
and stabilize menu scroll effect dependencies.
2026-05-22 15:18:31 +05:00
Abdullah bba61c3245 feat(website): sync product nav with hero scroll color transition
Drive the product page navbar from hero scroll progress with opacity-based
light-to-dark transitions, including fade back to light when leaving the AI section.
2026-05-22 15:18:31 +05:00
Abdullah a737a3c8fe feat(website): add scroll-driven product hero with stacked mobile layout
Replace the static product hero with a unified intro-to-AI scroll transition on
desktop and a stacked mobile layout, including taller preview sizing and updated
AI heading copy.
2026-05-22 15:18:31 +05:00
590 changed files with 31352 additions and 13809 deletions
+10 -9
View File
@@ -3,6 +3,8 @@ name: CI UI
on:
pull_request:
merge_group:
push:
branches: [main]
permissions:
contents: read
@@ -13,7 +15,7 @@ concurrency:
jobs:
changed-files-check:
if: github.event_name != 'merge_group'
if: github.event_name == 'pull_request'
uses: ./.github/workflows/changed-files.yaml
with:
files: |
@@ -40,7 +42,10 @@ jobs:
run: npx nx ${{ matrix.task }} twenty-ui
ui-sb-build:
needs: changed-files-check
if: needs.changed-files-check.outputs.any_changed == 'true'
if: >-
always() &&
(github.event_name == 'push' ||
needs.changed-files-check.outputs.any_changed == 'true')
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
@@ -62,8 +67,7 @@ jobs:
timeout-minutes: 30
runs-on: ubuntu-latest
needs: ui-sb-build
env:
STORYBOOK_URL: http://localhost:6007
if: always() && needs.ui-sb-build.result == 'success'
steps:
- name: Fetch custom Github Actions and base branch history
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
@@ -82,11 +86,8 @@ jobs:
run: |
cd packages/twenty-ui
npx playwright install
- name: Serve storybook & run tests
run: |
npx http-server packages/twenty-ui/storybook-static --port 6007 --silent &
timeout 30 bash -c 'until curl -sf http://localhost:6007 > /dev/null 2>&1; do sleep 1; done'
npx nx storybook:test twenty-ui
- name: Run storybook tests
run: npx nx storybook:test twenty-ui
- name: Upload screenshots for visual regression
if: always() && !cancelled()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
@@ -1,54 +1,33 @@
name: Visual Regression Dispatch
# Uses workflow_run to dispatch visual regression to ci-privileged.
# This runs in the context of the base repo (not the fork), so it has
# access to secrets — making it work for external contributor PRs.
# Dispatches visual regression processing to ci-privileged after CI completes.
# Runs in the context of the base repo (not the fork) so it has access to secrets,
# making it work for external contributor PRs.
on:
workflow_run:
workflows: ['CI Front', 'CI UI']
workflows: ['CI UI']
types: [completed]
permissions:
actions: read
contents: read
pull-requests: read
jobs:
dispatch:
dispatch-pr:
if: >-
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Determine project and artifact name
id: project
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const workflowName = context.payload.workflow_run.name;
if (workflowName === 'CI Front') {
core.setOutput('project', 'twenty-front');
core.setOutput('artifact_name', 'storybook-static');
core.setOutput('tarball_name', 'storybook-twenty-front-tarball');
core.setOutput('tarball_file', 'storybook-twenty-front.tar.gz');
core.setOutput('mode', 'storybook-tarball');
} else if (workflowName === 'CI UI') {
core.setOutput('project', 'twenty-ui');
core.setOutput('artifact_name', 'argos-screenshots-twenty-ui');
core.setOutput('tarball_name', 'argos-screenshots-twenty-ui-tarball');
core.setOutput('tarball_file', 'argos-screenshots-twenty-ui.tar.gz');
core.setOutput('mode', 'argos-screenshots');
} else {
core.setFailed(`Unexpected workflow: ${workflowName}`);
}
- name: Check if artifact exists
- name: Check if screenshots artifact exists
id: check-artifact
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const artifactName = '${{ steps.project.outputs.artifact_name }}';
const artifactName = 'argos-screenshots-twenty-ui';
const runId = context.payload.workflow_run.id;
const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({
@@ -61,7 +40,7 @@ jobs:
core.setOutput('exists', found ? 'true' : 'false');
if (!found) {
core.info(`Artifact "${artifactName}" not found in run ${runId} — build was likely skipped`);
core.info(`Artifact "${artifactName}" not found in run ${runId} — skipping`);
}
- name: Get PR number
@@ -73,8 +52,6 @@ jobs:
const headBranch = context.payload.workflow_run.head_branch;
const headRepo = context.payload.workflow_run.head_repository;
// workflow_run.pull_requests is empty for fork PRs,
// so fall back to searching by head label (owner:branch)
let pullRequests = context.payload.workflow_run.pull_requests;
let prNumber;
@@ -82,7 +59,7 @@ jobs:
prNumber = pullRequests[0].number;
} else {
const headLabel = `${headRepo.owner.login}:${headBranch}`;
core.info(`pull_requests is empty (likely a fork PR), searching by head label: ${headLabel}`);
core.info(`Searching for PR by head label: ${headLabel}`);
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
@@ -98,7 +75,7 @@ jobs:
}
if (!prNumber) {
core.info('No pull request found for this workflow run — skipping');
core.info('No pull request found — skipping');
core.setOutput('has_pr', 'false');
return;
}
@@ -107,45 +84,100 @@ jobs:
core.setOutput('has_pr', 'true');
core.info(`PR #${prNumber}`);
- name: Download artifact from triggering run
- name: Compute merge-base for Argos reference
if: steps.check-artifact.outputs.exists == 'true' && steps.pr-info.outputs.has_pr == 'true'
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
id: merge-base
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
name: ${{ steps.project.outputs.artifact_name }}
path: artifact-content
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
script: |
const headSha = context.payload.workflow_run.head_sha;
- name: Package artifact as tarball
if: steps.check-artifact.outputs.exists == 'true' && steps.pr-info.outputs.has_pr == 'true'
run: tar -czf /tmp/${{ steps.project.outputs.tarball_file }} -C artifact-content .
try {
const { data: comparison } = await github.rest.repos.compareCommitsWithBasehead({
owner: context.repo.owner,
repo: context.repo.repo,
basehead: `main...${headSha}`,
});
- name: Upload tarball
if: steps.check-artifact.outputs.exists == 'true' && steps.pr-info.outputs.has_pr == 'true'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ steps.project.outputs.tarball_name }}
path: /tmp/${{ steps.project.outputs.tarball_file }}
retention-days: 1
if (comparison.merge_base_commit?.sha) {
core.setOutput('sha', comparison.merge_base_commit.sha);
core.info(`Merge base: ${comparison.merge_base_commit.sha}`);
} else {
core.info('Could not determine merge base — will skip reference_commit');
core.setOutput('sha', '');
}
} catch (error) {
core.warning(`Failed to compute merge base: ${error instanceof Error ? error.message : String(error)}`);
core.setOutput('sha', '');
}
- name: Dispatch to ci-privileged
if: steps.check-artifact.outputs.exists == 'true' && steps.pr-info.outputs.has_pr == 'true'
env:
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
PR_NUMBER: ${{ steps.pr-info.outputs.pr_number }}
RUN_ID: ${{ github.run_id }}
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
REPOSITORY: ${{ github.repository }}
BRANCH: ${{ github.event.workflow_run.head_branch }}
COMMIT: ${{ github.event.workflow_run.head_sha }}
REFERENCE_COMMIT: ${{ steps.merge-base.outputs.sha }}
run: |
ARGS=(
--method POST
-f event_type=visual-regression
-f "client_payload[pr_number]=$PR_NUMBER"
-f "client_payload[run_id]=$WORKFLOW_RUN_ID"
-f "client_payload[repo]=$REPOSITORY"
-f "client_payload[branch]=$BRANCH"
-f "client_payload[commit]=$COMMIT"
)
if [ -n "$REFERENCE_COMMIT" ]; then
ARGS+=(-f "client_payload[reference_commit]=$REFERENCE_COMMIT")
fi
gh api repos/twentyhq/ci-privileged/dispatches "${ARGS[@]}"
dispatch-main:
if: >-
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Check if screenshots artifact exists
id: check-artifact
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const runId = context.payload.workflow_run.id;
const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: runId,
});
const found = artifacts.artifacts.some(a => a.name === 'argos-screenshots-twenty-ui');
core.setOutput('exists', found ? 'true' : 'false');
if (!found) {
core.info(`Artifact not found in run ${runId} — skipping`);
}
- name: Dispatch to ci-privileged
if: steps.check-artifact.outputs.exists == 'true'
env:
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
REPOSITORY: ${{ github.repository }}
PROJECT: ${{ steps.project.outputs.project }}
BRANCH: ${{ github.event.workflow_run.head_branch }}
COMMIT: ${{ github.event.workflow_run.head_sha }}
MODE: ${{ steps.project.outputs.mode }}
run: |
gh api repos/twentyhq/ci-privileged/dispatches \
--method POST \
-f event_type=visual-regression \
-f "client_payload[pr_number]=$PR_NUMBER" \
-f "client_payload[run_id]=$RUN_ID" \
-f "client_payload[run_id]=$WORKFLOW_RUN_ID" \
-f "client_payload[repo]=$REPOSITORY" \
-f "client_payload[project]=$PROJECT" \
-f "client_payload[branch]=$BRANCH" \
-f "client_payload[commit]=$COMMIT" \
-f "client_payload[mode]=$MODE"
-f "client_payload[commit]=$COMMIT"
+1 -6
View File
@@ -147,13 +147,9 @@ Want to go deeper? Read the <a href="https://docs.twenty.com/user-guide/introduc
- <a href="https://nestjs.com/"><img src="./packages/twenty-website/public/images/readme/stack-nestjs.svg" width="14" height="14"/> NestJS</a>, with <a href="https://bullmq.io/">BullMQ</a>, <a href="https://www.postgresql.org/"><img src="./packages/twenty-website/public/images/readme/stack-postgresql.svg" width="14" height="14"/> PostgreSQL</a>, <a href="https://redis.io/"><img src="./packages/twenty-website/public/images/readme/stack-redis.svg" width="14" height="14"/> Redis</a>
- <a href="https://reactjs.org/"><img src="./packages/twenty-website/public/images/readme/stack-react.svg" width="14" height="14"/> React</a>, with <a href="https://jotai.org/">Jotai</a>, <a href="https://linaria.dev/">Linaria</a> and <a href="https://lingui.dev/">Lingui</a>
# Thanks
<p align="center">
<a href="https://www.chromatic.com/"><img src="./packages/twenty-website/public/images/readme/chromatic.webp" height="28" alt="Chromatic" /></a>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://greptile.com"><img src="./packages/twenty-website/public/images/readme/greptile.webp" height="28" alt="Greptile" /></a>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://sentry.io/"><img src="./packages/twenty-website/public/images/readme/sentry.webp" height="28" alt="Sentry" /></a>
@@ -161,8 +157,7 @@ Want to go deeper? Read the <a href="https://docs.twenty.com/user-guide/introduc
<a href="https://crowdin.com/"><img src="./packages/twenty-website/public/images/readme/crowdin.webp" height="28" alt="Crowdin" /></a>
</p>
Thanks to these amazing services that we use and recommend for UI testing (Chromatic), code review (Greptile), catching bugs (Sentry) and translating (Crowdin).
Thanks to these amazing services that we use and recommend for code review (Greptile), catching bugs (Sentry) and translating (Crowdin).
# Join the Community
-19
View File
@@ -220,25 +220,6 @@
}
}
},
"chromatic": {
"executor": "nx:run-commands",
"options": {
"cwd": "{projectRoot}",
"commands": [
{
"command": "nx storybook:build {projectName}",
"forwardAllArgs": false
},
"chromatic --storybook-build-dir=storybook-static {args.ci}"
],
"parallel": false
},
"configurations": {
"ci": {
"ci": "--exit-zero-on-changes"
}
}
},
"@nx/jest:jest": {
"cache": true,
"inputs": [
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "create-twenty-app",
"version": "2.9.0",
"version": "2.10.0",
"description": "Command-line interface to create Twenty application",
"main": "dist/cli.cjs",
"bin": "dist/cli.cjs",
@@ -3,7 +3,7 @@ import { NavigationMenuItemType } from 'twenty-shared/types';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
export default defineNavigationMenuItem({
universalIdentifier: 'c1a2b3c4-0001-4a7b-8c9d-0e1f2a3b4c5d',
universalIdentifier: 'e8031eca-d6ea-4a4b-b828-38227dba896a',
position: 0,
type: NavigationMenuItemType.OBJECT,
targetObjectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
@@ -0,0 +1,10 @@
import { defineViewField } from 'twenty-sdk/define';
import { ALL_POST_CARDS_VIEW_ID } from '../views/all-post-cards.view';
export default defineViewField({
fieldMetadataUniversalIdentifier: '7b57bd63-5a4c-46ca-9d52-42c8f02d1df6',
position: 5,
universalIdentifier: 'cd582d11-ea21-4dc3-b9c1-0298ce3b6b54',
viewUniversalIdentifier: ALL_POST_CARDS_VIEW_ID,
isVisible: true,
});
@@ -0,0 +1,32 @@
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn
# codegen
generated
# dev
/dist/
.twenty
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files
.env*
# typescript
*.tsbuildinfo
*.d.ts
@@ -0,0 +1,70 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript", "import", "unicorn"],
"categories": {
"correctness": "off"
},
"ignorePatterns": ["node_modules", "dist"],
"rules": {
"func-style": ["error", "declaration", { "allowArrowFunctions": true }],
"no-console": [
"warn",
{ "allow": ["group", "groupCollapsed", "groupEnd"] }
],
"no-control-regex": "off",
"no-debugger": "error",
"no-duplicate-imports": "error",
"no-undef": "off",
"no-unused-vars": "off",
"no-redeclare": "off",
"import/no-duplicates": "error",
"typescript/no-redeclare": "error",
"typescript/ban-ts-comment": "error",
"typescript/consistent-type-imports": [
"error",
{
"prefer": "type-imports",
"fixStyle": "inline-type-imports"
}
],
"typescript/explicit-function-return-type": "off",
"typescript/explicit-module-boundary-types": "off",
"typescript/no-empty-object-type": [
"error",
{
"allowInterfaces": "with-single-extends"
}
],
"typescript/no-empty-function": "off",
"typescript/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
],
"typescript/no-explicit-any": "off"
},
"overrides": [
{
"files": ["**/*.logic-function.ts", "**/logic-functions/**/*.ts"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["twenty-shared", "twenty-shared/*"],
"message": "Logic functions must not import from twenty-shared directly. Import runtime types and helpers from `twenty-sdk/logic-function` instead so the logic-function bundle stays minimal."
}
]
}
]
}
}
]
}
@@ -0,0 +1 @@
nodeLinker: node-modules
@@ -0,0 +1,114 @@
# People Data Labs enrichment app
Enriches **Person** and **Company** records with [People Data Labs](https://www.peopledatalabs.com/) (PDL) data.
> **Status: data-model scaffold.** This package defines the fields, relation, indexes,
> views, role, and manifest. The enrichment **logic function (the "mapper") is not yet
> implemented** — see [What the mapper must do](#what-the-mapper-must-do).
---
## Data-model decisions
### Bundle scope
Only the core PDL company fields are defined. Premium / Comprehensive / specialized fields
(`inferred_revenue`, `linkedin_follower_count`, employee growth/churn/tenure, parent /
subsidiary, exec movement, top employers, `funding_details`, …) are **out of scope** for this app.
### Enums → SELECT / MULTI_SELECT
Every PDL enum that has a canonical file is a SELECT, **validated 0-missing/0-extra against
PDL schema v34.1**:
| Field | Type | Options |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------ |
| `pdlSeniority` (`job_title_levels`, array) | MULTI_SELECT | 10 |
| `pdlFundingStages` (`funding_stages`, array) | MULTI_SELECT | 29 |
| `pdlIndustry` / `pdlJobCompanyIndustry` (`industry`) | SELECT | 147 |
| `pdlJobTitleSubRole` (`job_title_sub_role`) | SELECT | 106 |
| `pdlJobTitleClass`, `pdlInferredSalary`, `pdlSex`, `pdlCompanyType`, `pdlSizeRange`, `pdlJobCompanySize`, `pdlLatestFundingStage`, `pdlLocationContinent`, `pdlLocationMetro`, `pdlMicExchange` | SELECT | 5 / 11 / 2 / 6 / 8 / 8 / 29 / 7 / 384 / 70 |
- Option `value`s are normalized to **GraphQL enum names** (`united states``UNITED_STATES`):
uppercase, accents stripped, non-alphanumeric → `_`, digit-leading prefixed.
- Option `universalIdentifier`s are **unique per field** (shared enums like industry get a
separate id-set per field).
- **Stays `TEXT`** (no canonical PDL enum file exists): `pdlIndustryDetail` (`industry_v2`),
`pdlJobOnetCode`, `pdlLocationRegion`.
### Standard-field mapping
`pdl*` shadows are **removed** where an equivalent standard field exists; the mapper writes
the standard field instead:
| Object | Removed shadow → standard target |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Person | `pdlLinkedinUrl``linkedinLink`, `pdlJobTitle``jobTitle`, `pdlFullName``name`, `pdlWorkEmail`/`pdlPersonalEmails``emails`, `pdlMobilePhone`/`pdlPhoneNumbers``phones` |
| Company | `pdlLinkedinUrl``linkedinLink`, `pdlWebsite``domainName`, `pdlDisplayName``name` |
Shadows are **kept** where no reliable standard field is available: `pdlEmployeeCount`,
`pdlTwitterUrl`.
_Trade-off:_ PDL's work/personal-email and mobile/other-phone distinction is dropped (folded
into the standard bags).
### Location → ADDRESS composite
- **Company** location → the **standard `address`** composite (street/city/state/postcode/country/geo).
- **Person** has no standard address field → dedicated **`pdlLocation` (ADDRESS)**.
- `pdlLocationMetro` (both) and `pdlLocationContinent` (company) stay SELECT — ADDRESS has no slot.
_Trade-off:_ ADDRESS `country` is free text, so the country SELECT was dropped.
### Relation
Dedicated **`pdlCurrentCompany`** (Person `MANY_TO_ONE` → Company) ↔ inverse
**`pdlCurrentEmployees`** (Company `ONE_TO_MANY` → Person). Deliberately **not** the standard
`company` relation, so PDL's detected employer can't overwrite the user's CRM account link.
### Enrichment metadata
- `pdlId` — PDL record id (re-enrich by id: more precise than by email).
- `pdlLikelihood` (Person, NUMBER) — PDL match confidence 110.
- `pdlEnrichmentStatus` (SELECT: `MATCHED` / `NOT_FOUND` / `ERROR`) — distinguishes
"no match" from "never tried" (drives re-enrichment scheduling).
- `pdlLastEnrichedAt` (DATE_TIME), `pdlRawPayload` (RAW_JSON, full response).
### Other
- `pdlTotalFunding` is `CURRENCY` (mapper must convert the bare USD float → micros).
- **Indexes**: `pdlId` and `pdlLastEnrichedAt` on both objects.
- **Views**: a curated "People Data Labs" TABLE view per object.
- **Role**: read/update on Person & Company (object-level; tighten to field-scoped later).
---
## What the mapper must do
The logic function (to be built) must:
**Orchestration**
1. Trigger via manual command-menu action / record create / batch (TBD).
2. Call PDL Person and/or Company Enrichment with `PDL_API_KEY`; pass `min_likelihood` /
`required_fields` to control match quality.
3. On `200` → write fields + set `pdlEnrichmentStatus = MATCHED`; on `404`
`NOT_FOUND`; on error → `ERROR`.
4. Respect PDL rate limits (queue / throttle on `429`).
5. **TTL guard**: skip re-enrichment if `pdlLastEnrichedAt` is recent; prefer re-enriching by `pdlId`.
**Field writing**
6. Write **standard fields** (fill-only-if-empty to avoid overwriting user data):
Person `name`, `emails`, `phones`, `linkedinLink`, `jobTitle`; Company `name`,
`domainName`, `linkedinLink`, `address`.
7. Write `pdl*` fields for everything else.
8. **SELECT guard**: only write a SELECT/MULTI_SELECT value if the normalized value exists in
the field's option set; otherwise skip and keep it in `pdlRawPayload` (handles PDL schema
versions newer than v34.1). Use the same normalization as the option `value`s.
9. **MULTI_SELECT** arrays: `job_title_levels``pdlSeniority`; `funding_stages``pdlFundingStages`.
10. **CURRENCY**: `total_funding_raised` (USD float) → `{ amountMicros: value × 1_000_000, currencyCode: 'USD' }`.
11. **ADDRESS**: split PDL `location.*` into the composite — Company → standard `address`,
Person → `pdlLocation`.
12. **Relation**: resolve `job_company_id` → find/upsert a Company record → link `pdlCurrentCompany`.
13. **Dates**: handle partial PDL dates (`YYYY`, `YYYY-MM`) for `job_start_date`,
`last_funding_date`, `birth_date`.
14. Always set `pdlId`, `pdlLastEnrichedAt`, `pdlRawPayload`, `pdlLikelihood` (person).
@@ -0,0 +1,36 @@
{
"name": "people-data-labs",
"version": "0.1.0",
"description": "People Data Labs enrichment app for Twenty",
"license": "MIT",
"engines": {
"node": "^24.5.0",
"npm": "please-use-yarn",
"yarn": ">=4.0.2"
},
"keywords": [
"twenty-app"
],
"packageManager": "yarn@4.9.2",
"scripts": {
"twenty": "twenty",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json .",
"test": "vitest run --passWithNoTests",
"test:watch": "vitest"
},
"dependencies": {
"twenty-client-sdk": "2.4.0",
"twenty-sdk": "2.4.0"
},
"devDependencies": {
"@types/node": "^24.7.2",
"@types/react": "^19.0.0",
"oxlint": "^0.16.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"typescript": "^5.9.3",
"vite-tsconfig-paths": "^4.2.1",
"vitest": "^3.1.1"
}
}
@@ -0,0 +1,16 @@
import { defineApplication } from 'twenty-sdk/define';
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
export default defineApplication({
universalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
displayName: 'People Data Labs',
description: 'Enrich People and Companies with People Data Labs data.',
serverVariables: {
PDL_API_KEY: {
description: 'People Data Labs API key',
isSecret: true,
isRequired: true,
},
},
});
@@ -0,0 +1,19 @@
import { type SelectOptionMeta } from 'src/types/select-option-meta.type';
export const ENRICHMENT_STATUS_OPTIONS: readonly SelectOptionMeta[] = [
{
key: 'matched',
value: 'MATCHED',
label: 'Matched',
color: 'green',
position: 0,
},
{
key: 'notFound',
value: 'NOT_FOUND',
label: 'No Match',
color: 'gray',
position: 1,
},
{ key: 'error', value: 'ERROR', label: 'Error', color: 'red', position: 2 },
];
@@ -0,0 +1,195 @@
import { type SelectOptionMeta } from 'src/types/select-option-meta.type';
export const FUNDING_STAGE_OPTIONS: readonly SelectOptionMeta[] = [
{
key: 'angel',
value: 'ANGEL',
label: 'Angel',
color: 'blue',
position: 0,
},
{
key: 'convertibleNote',
value: 'CONVERTIBLE_NOTE',
label: 'Convertible Note',
color: 'red',
position: 1,
},
{
key: 'corporateRound',
value: 'CORPORATE_ROUND',
label: 'Corporate Round',
color: 'green',
position: 2,
},
{
key: 'debtFinancing',
value: 'DEBT_FINANCING',
label: 'Debt Financing',
color: 'orange',
position: 3,
},
{
key: 'equityCrowdfunding',
value: 'EQUITY_CROWDFUNDING',
label: 'Equity Crowdfunding',
color: 'purple',
position: 4,
},
{
key: 'fundingRound',
value: 'FUNDING_ROUND',
label: 'Funding Round',
color: 'yellow',
position: 5,
},
{ key: 'grant', value: 'GRANT', label: 'Grant', color: 'pink', position: 6 },
{
key: 'initialCoinOffering',
value: 'INITIAL_COIN_OFFERING',
label: 'Initial Coin Offering',
color: 'cyan',
position: 7,
},
{
key: 'nonEquityAssistance',
value: 'NON_EQUITY_ASSISTANCE',
label: 'Non-Equity Assistance',
color: 'brown',
position: 8,
},
{
key: 'postIpoDebt',
value: 'POST_IPO_DEBT',
label: 'Post-IPO Debt',
color: 'lime',
position: 9,
},
{
key: 'postIpoEquity',
value: 'POST_IPO_EQUITY',
label: 'Post-IPO Equity',
color: 'violet',
position: 10,
},
{
key: 'postIpoSecondary',
value: 'POST_IPO_SECONDARY',
label: 'Post-IPO Secondary',
color: 'gold',
position: 11,
},
{
key: 'preSeed',
value: 'PRE_SEED',
label: 'Pre-Seed',
color: 'turquoise',
position: 12,
},
{
key: 'privateEquity',
value: 'PRIVATE_EQUITY',
label: 'Private Equity',
color: 'crimson',
position: 13,
},
{
key: 'productCrowdfunding',
value: 'PRODUCT_CROWDFUNDING',
label: 'Product Crowdfunding',
color: 'sky',
position: 14,
},
{
key: 'secondaryMarket',
value: 'SECONDARY_MARKET',
label: 'Secondary Market',
color: 'amber',
position: 15,
},
{ key: 'seed', value: 'SEED', label: 'Seed', color: 'plum', position: 16 },
{
key: 'seriesA',
value: 'SERIES_A',
label: 'Series A',
color: 'grass',
position: 17,
},
{
key: 'seriesB',
value: 'SERIES_B',
label: 'Series B',
color: 'tomato',
position: 18,
},
{
key: 'seriesC',
value: 'SERIES_C',
label: 'Series C',
color: 'iris',
position: 19,
},
{
key: 'seriesD',
value: 'SERIES_D',
label: 'Series D',
color: 'mint',
position: 20,
},
{
key: 'seriesE',
value: 'SERIES_E',
label: 'Series E',
color: 'ruby',
position: 21,
},
{
key: 'seriesF',
value: 'SERIES_F',
label: 'Series F',
color: 'bronze',
position: 22,
},
{
key: 'seriesG',
value: 'SERIES_G',
label: 'Series G',
color: 'jade',
position: 23,
},
{
key: 'seriesH',
value: 'SERIES_H',
label: 'Series H',
color: 'gray',
position: 24,
},
{
key: 'seriesI',
value: 'SERIES_I',
label: 'Series I',
color: 'blue',
position: 25,
},
{
key: 'seriesJ',
value: 'SERIES_J',
label: 'Series J',
color: 'red',
position: 26,
},
{
key: 'seriesUnknown',
value: 'SERIES_UNKNOWN',
label: 'Series Unknown',
color: 'green',
position: 27,
},
{
key: 'undisclosed',
value: 'UNDISCLOSED',
label: 'Undisclosed',
color: 'orange',
position: 28,
},
];
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,60 @@
import { type SelectOptionMeta } from 'src/types/select-option-meta.type';
export const SIZE_OPTIONS: readonly SelectOptionMeta[] = [
{
key: 'oneToTen',
value: 'ONE_TO_TEN',
label: '1-10',
color: 'blue',
position: 0,
},
{
key: 'elevenToFifty',
value: 'ELEVEN_TO_FIFTY',
label: '11-50',
color: 'red',
position: 1,
},
{
key: 'fiftyOneToTwoHundred',
value: 'FIFTY_ONE_TO_TWO_HUNDRED',
label: '51-200',
color: 'green',
position: 2,
},
{
key: 'twoHundredOneToFiveHundred',
value: 'TWO_HUNDRED_ONE_TO_FIVE_HUNDRED',
label: '201-500',
color: 'orange',
position: 3,
},
{
key: 'fiveHundredOneToOneThousand',
value: 'FIVE_HUNDRED_ONE_TO_ONE_THOUSAND',
label: '501-1000',
color: 'purple',
position: 4,
},
{
key: 'oneThousandOneToFiveThousand',
value: 'ONE_THOUSAND_ONE_TO_FIVE_THOUSAND',
label: '1001-5000',
color: 'yellow',
position: 5,
},
{
key: 'fiveThousandOneToTenThousand',
value: 'FIVE_THOUSAND_ONE_TO_TEN_THOUSAND',
label: '5001-10000',
color: 'pink',
position: 6,
},
{
key: 'tenThousandOnePlus',
value: 'TEN_THOUSAND_ONE_PLUS',
label: '10001+',
color: 'cyan',
position: 7,
},
];
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlAffiliatedProfiles,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.ARRAY,
name: 'pdlAffiliatedProfiles',
label: 'Affiliated Profiles',
description: 'Affiliated company profiles returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlAlternativeDomains,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.ARRAY,
name: 'pdlAlternativeDomains',
label: 'Alternative Domains',
description: 'Alternative domains returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlAlternativeNames,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.ARRAY,
name: 'pdlAlternativeNames',
label: 'Alternative Names',
description: 'Alternative names returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,65 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlCompanyType,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlCompanyType',
label: 'Company Type',
description: 'People Data Labs canonical company type.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyType.public,
value: 'PUBLIC',
label: 'Public',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyType.private,
value: 'PRIVATE',
label: 'Private',
color: 'red',
position: 1,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyType.publicSubsidiary,
value: 'PUBLIC_SUBSIDIARY',
label: 'Public Subsidiary',
color: 'green',
position: 2,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyType.educational,
value: 'EDUCATIONAL',
label: 'Educational',
color: 'orange',
position: 3,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyType.government,
value: 'GOVERNMENT',
label: 'Government',
color: 'purple',
position: 4,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyType.nonprofit,
value: 'NONPROFIT',
label: 'Nonprofit',
color: 'yellow',
position: 5,
},
],
});
@@ -0,0 +1,28 @@
import {
defineField,
FieldType,
RelationType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlCurrentEmployees,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.RELATION,
name: 'pdlCurrentEmployees',
label: 'PDL Current Employees',
description:
'People whose current employer is this company, per People Data Labs.',
relationTargetObjectMetadataUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
relationTargetFieldMetadataUniversalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlCurrentCompany,
universalSettings: {
relationType: RelationType.ONE_TO_MANY,
},
icon: 'IconUsers',
});
@@ -0,0 +1,20 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlEmployeeCountByCountry,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlEmployeeCountByCountry',
label: 'Employee Count by Country',
description:
'Employee count broken down by country returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlEmployeeCount,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.NUMBER,
name: 'pdlEmployeeCount',
label: 'Employees',
description: 'Exact employee count returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,28 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { ENRICHMENT_STATUS_OPTIONS } from 'src/constants/enrichment-status-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlEnrichmentStatus,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlEnrichmentStatus',
label: 'Enrichment Status',
description: 'Outcome of the latest People Data Labs enrichment attempt.',
isNullable: true,
options: buildSelectOptions(
ENRICHMENT_STATUS_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyEnrichmentStatus,
),
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlFacebookUrl,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.LINKS,
name: 'pdlFacebookUrl',
label: 'Facebook',
description: 'Facebook page returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlFoundedYear,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.NUMBER,
name: 'pdlFoundedYear',
label: 'Founded Year',
description: 'Founding year returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,27 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { FUNDING_STAGE_OPTIONS } from 'src/constants/funding-stage-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlFundingStages,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.MULTI_SELECT,
name: 'pdlFundingStages',
label: 'Funding Stages',
description: 'People Data Labs canonical funding stages.',
isNullable: true,
options: buildSelectOptions(
FUNDING_STAGE_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.fundingStage,
),
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlHeadline,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlHeadline',
label: 'Headline',
description: 'People Data Labs company headline or summary.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlId,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlId',
label: 'PDL ID',
description: 'People Data Labs company identifier.',
isNullable: true,
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlIndustryDetail,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlIndustryDetail',
label: 'Industry (detailed)',
description: 'Detailed People Data Labs industry v2 value.',
isNullable: true,
});
@@ -0,0 +1,27 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { INDUSTRY_OPTIONS } from 'src/constants/industry-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlIndustry,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlIndustry',
label: 'Industry',
description: 'People Data Labs canonical industry.',
isNullable: true,
options: buildSelectOptions(
INDUSTRY_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyIndustry,
),
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlLastEnrichedAt,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.DATE_TIME,
name: 'pdlLastEnrichedAt',
label: 'Last Enriched At',
description: 'Timestamp of the latest People Data Labs enrichment.',
isNullable: true,
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlLastFundingDate,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.DATE,
name: 'pdlLastFundingDate',
label: 'Last Funding Date',
description: 'Date of the latest funding round returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,28 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { FUNDING_STAGE_OPTIONS } from 'src/constants/funding-stage-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlLatestFundingStage,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlLatestFundingStage',
label: 'Latest Funding Stage',
description: 'People Data Labs canonical latest funding stage.',
isNullable: true,
options: buildSelectOptions(
FUNDING_STAGE_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.fundingStage,
),
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlLinkedinId,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlLinkedinId',
label: 'LinkedIn ID',
description: 'LinkedIn identifier returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,79 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlLocationContinent,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlLocationContinent',
label: 'Continent',
description: 'People Data Labs canonical continent.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyLocationContinent
.africa,
value: 'AFRICA',
label: 'Africa',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyLocationContinent
.antarctica,
value: 'ANTARCTICA',
label: 'Antarctica',
color: 'red',
position: 1,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyLocationContinent.asia,
value: 'ASIA',
label: 'Asia',
color: 'green',
position: 2,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyLocationContinent
.europe,
value: 'EUROPE',
label: 'Europe',
color: 'orange',
position: 3,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyLocationContinent
.northAmerica,
value: 'NORTH_AMERICA',
label: 'North America',
color: 'purple',
position: 4,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyLocationContinent
.oceania,
value: 'OCEANIA',
label: 'Oceania',
color: 'yellow',
position: 5,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyLocationContinent
.southAmerica,
value: 'SOUTH_AMERICA',
label: 'South America',
color: 'pink',
position: 6,
},
],
});
@@ -0,0 +1,27 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { METRO_OPTIONS } from 'src/constants/metro-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlLocationMetro,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlLocationMetro',
label: 'Metro Area',
description: 'People Data Labs canonical metro area.',
isNullable: true,
options: buildSelectOptions(
METRO_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyLocationMetro,
),
});
@@ -0,0 +1,513 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlMicExchange,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlMicExchange',
label: 'Stock Exchange (MIC)',
description: 'People Data Labs canonical market identifier code.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.aqse,
value: 'AQSE',
label: 'AQSE',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.arcx,
value: 'ARCX',
label: 'ARCX',
color: 'red',
position: 1,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.asex,
value: 'ASEX',
label: 'ASEX',
color: 'green',
position: 2,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.bcxe,
value: 'BCXE',
label: 'BCXE',
color: 'orange',
position: 3,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.bvmf,
value: 'BVMF',
label: 'BVMF',
color: 'purple',
position: 4,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.dsmd,
value: 'DSMD',
label: 'DSMD',
color: 'yellow',
position: 5,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.misx,
value: 'MISX',
label: 'MISX',
color: 'pink',
position: 6,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.neoe,
value: 'NEOE',
label: 'NEOE',
color: 'cyan',
position: 7,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xams,
value: 'XAMS',
label: 'XAMS',
color: 'brown',
position: 8,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xase,
value: 'XASE',
label: 'XASE',
color: 'lime',
position: 9,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xasx,
value: 'XASX',
label: 'XASX',
color: 'violet',
position: 10,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xber,
value: 'XBER',
label: 'XBER',
color: 'gold',
position: 11,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xbkk,
value: 'XBKK',
label: 'XBKK',
color: 'turquoise',
position: 12,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xbog,
value: 'XBOG',
label: 'XBOG',
color: 'crimson',
position: 13,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xbom,
value: 'XBOM',
label: 'XBOM',
color: 'sky',
position: 14,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xbru,
value: 'XBRU',
label: 'XBRU',
color: 'amber',
position: 15,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xbsp,
value: 'XBSP',
label: 'XBSP',
color: 'plum',
position: 16,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xbud,
value: 'XBUD',
label: 'XBUD',
color: 'grass',
position: 17,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xbue,
value: 'XBUE',
label: 'XBUE',
color: 'tomato',
position: 18,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xcai,
value: 'XCAI',
label: 'XCAI',
color: 'iris',
position: 19,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xcbo,
value: 'XCBO',
label: 'XCBO',
color: 'mint',
position: 20,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xcnq,
value: 'XCNQ',
label: 'XCNQ',
color: 'ruby',
position: 21,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xcse,
value: 'XCSE',
label: 'XCSE',
color: 'bronze',
position: 22,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xdfm,
value: 'XDFM',
label: 'XDFM',
color: 'jade',
position: 23,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xdub,
value: 'XDUB',
label: 'XDUB',
color: 'gray',
position: 24,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xdus,
value: 'XDUS',
label: 'XDUS',
color: 'blue',
position: 25,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xeqy,
value: 'XEQY',
label: 'XEQY',
color: 'red',
position: 26,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xfra,
value: 'XFRA',
label: 'XFRA',
color: 'green',
position: 27,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xham,
value: 'XHAM',
label: 'XHAM',
color: 'orange',
position: 28,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xhel,
value: 'XHEL',
label: 'XHEL',
color: 'purple',
position: 29,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xhkg,
value: 'XHKG',
label: 'XHKG',
color: 'yellow',
position: 30,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xice,
value: 'XICE',
label: 'XICE',
color: 'pink',
position: 31,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xidx,
value: 'XIDX',
label: 'XIDX',
color: 'cyan',
position: 32,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xjpx,
value: 'XJPX',
label: 'XJPX',
color: 'brown',
position: 33,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xjse,
value: 'XJSE',
label: 'XJSE',
color: 'lime',
position: 34,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xkls,
value: 'XKLS',
label: 'XKLS',
color: 'violet',
position: 35,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xkos,
value: 'XKOS',
label: 'XKOS',
color: 'gold',
position: 36,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xkrx,
value: 'XKRX',
label: 'XKRX',
color: 'turquoise',
position: 37,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xkuw,
value: 'XKUW',
label: 'XKUW',
color: 'crimson',
position: 38,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xlis,
value: 'XLIS',
label: 'XLIS',
color: 'sky',
position: 39,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xlon,
value: 'XLON',
label: 'XLON',
color: 'amber',
position: 40,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xmad,
value: 'XMAD',
label: 'XMAD',
color: 'plum',
position: 41,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xmex,
value: 'XMEX',
label: 'XMEX',
color: 'grass',
position: 42,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xmil,
value: 'XMIL',
label: 'XMIL',
color: 'tomato',
position: 43,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xmun,
value: 'XMUN',
label: 'XMUN',
color: 'iris',
position: 44,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xnas,
value: 'XNAS',
label: 'XNAS',
color: 'mint',
position: 45,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xnse,
value: 'XNSE',
label: 'XNSE',
color: 'ruby',
position: 46,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xnys,
value: 'XNYS',
label: 'XNYS',
color: 'bronze',
position: 47,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xnze,
value: 'XNZE',
label: 'XNZE',
color: 'jade',
position: 48,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xosl,
value: 'XOSL',
label: 'XOSL',
color: 'gray',
position: 49,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xotc,
value: 'XOTC',
label: 'XOTC',
color: 'blue',
position: 50,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xpar,
value: 'XPAR',
label: 'XPAR',
color: 'red',
position: 51,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xpra,
value: 'XPRA',
label: 'XPRA',
color: 'green',
position: 52,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xris,
value: 'XRIS',
label: 'XRIS',
color: 'orange',
position: 53,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xsau,
value: 'XSAU',
label: 'XSAU',
color: 'purple',
position: 54,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xses,
value: 'XSES',
label: 'XSES',
color: 'yellow',
position: 55,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xsgo,
value: 'XSGO',
label: 'XSGO',
color: 'pink',
position: 56,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xshe,
value: 'XSHE',
label: 'XSHE',
color: 'cyan',
position: 57,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xshg,
value: 'XSHG',
label: 'XSHG',
color: 'brown',
position: 58,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xstc,
value: 'XSTC',
label: 'XSTC',
color: 'lime',
position: 59,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xsto,
value: 'XSTO',
label: 'XSTO',
color: 'violet',
position: 60,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xstu,
value: 'XSTU',
label: 'XSTU',
color: 'gold',
position: 61,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xswx,
value: 'XSWX',
label: 'XSWX',
color: 'turquoise',
position: 62,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xtae,
value: 'XTAE',
label: 'XTAE',
color: 'crimson',
position: 63,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xtai,
value: 'XTAI',
label: 'XTAI',
color: 'sky',
position: 64,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xtal,
value: 'XTAL',
label: 'XTAL',
color: 'amber',
position: 65,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xtse,
value: 'XTSE',
label: 'XTSE',
color: 'plum',
position: 66,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xtsx,
value: 'XTSX',
label: 'XTSX',
color: 'grass',
position: 67,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xwar,
value: 'XWAR',
label: 'XWAR',
color: 'tomato',
position: 68,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.companyMicExchange.xwbo,
value: 'XWBO',
label: 'XWBO',
color: 'iris',
position: 69,
},
],
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlNaics,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlNaics',
label: 'NAICS Codes',
description: 'NAICS classification codes returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlNumberFundingRounds,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.NUMBER,
name: 'pdlNumberFundingRounds',
label: 'Number of Funding Rounds',
description: 'Number of funding rounds returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlRawPayload,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlRawPayload',
label: 'PDL Raw Payload',
description: 'Full People Data Labs company enrichment response.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlSic,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlSic',
label: 'SIC Codes',
description: 'SIC classification codes returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,27 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { SIZE_OPTIONS } from 'src/constants/size-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlSizeRange,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlSizeRange',
label: 'Employee Range',
description: 'People Data Labs canonical self-reported employee range.',
isNullable: true,
options: buildSelectOptions(
SIZE_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.sizeRange,
),
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlSummary,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlSummary',
label: 'Summary',
description: 'Company summary returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlTags,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.ARRAY,
name: 'pdlTags',
label: 'Tags',
description: 'Tags returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlTicker,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlTicker',
label: 'Ticker',
description: 'Company ticker returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlTotalFunding,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.CURRENCY,
name: 'pdlTotalFunding',
label: 'Total Funding Raised',
description: 'Total funding raised in USD returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlTwitterUrl,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.LINKS,
name: 'pdlTwitterUrl',
label: 'X / Twitter',
description: 'X or Twitter company profile returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlBirthDate,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.DATE,
name: 'pdlBirthDate',
label: 'Birth Date',
description: 'Birth date returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlBirthYear,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.NUMBER,
name: 'pdlBirthYear',
label: 'Birth Year',
description: 'Birth year returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlCertifications,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlCertifications',
label: 'Certifications',
description: 'Certifications returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,26 @@
import {
defineField,
FieldType,
RelationType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlCurrentCompany,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.RELATION,
name: 'pdlCurrentCompany',
label: 'PDL Current Company',
description: 'Current employer detected by People Data Labs.',
relationTargetObjectMetadataUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
relationTargetFieldMetadataUniversalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlCurrentEmployees,
universalSettings: {
relationType: RelationType.MANY_TO_ONE,
},
icon: 'IconBuilding',
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlEducation,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlEducation',
label: 'Education History',
description: 'Education history returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,28 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { ENRICHMENT_STATUS_OPTIONS } from 'src/constants/enrichment-status-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlEnrichmentStatus,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlEnrichmentStatus',
label: 'Enrichment Status',
description: 'Outcome of the latest People Data Labs enrichment attempt.',
isNullable: true,
options: buildSelectOptions(
ENRICHMENT_STATUS_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personEnrichmentStatus,
),
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlExperience,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlExperience',
label: 'Experience History',
description: 'Experience history returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlFacebookUrl,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.LINKS,
name: 'pdlFacebookUrl',
label: 'Facebook',
description: 'Facebook profile returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlGithubUrl,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.LINKS,
name: 'pdlGithubUrl',
label: 'GitHub',
description: 'GitHub profile returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlHeadline,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlHeadline',
label: 'Headline',
description: 'People Data Labs person headline or job summary.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlId,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlId',
label: 'PDL ID',
description: 'People Data Labs person identifier.',
isNullable: true,
});
@@ -0,0 +1,27 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { INDUSTRY_OPTIONS } from 'src/constants/industry-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlIndustry,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlIndustry',
label: 'Industry',
description: 'People Data Labs canonical industry.',
isNullable: true,
options: buildSelectOptions(
INDUSTRY_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personIndustry,
),
});
@@ -0,0 +1,111 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlInferredSalary,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlInferredSalary',
label: 'Inferred Salary (range)',
description: 'People Data Labs canonical inferred salary range.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.under20000,
value: 'UNDER_20000',
label: '<20,000',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from20000To25000,
value: 'FROM_20000_TO_25000',
label: '20,000-25,000',
color: 'red',
position: 1,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from25000To35000,
value: 'FROM_25000_TO_35000',
label: '25,000-35,000',
color: 'green',
position: 2,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from35000To45000,
value: 'FROM_35000_TO_45000',
label: '35,000-45,000',
color: 'orange',
position: 3,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from45000To55000,
value: 'FROM_45000_TO_55000',
label: '45,000-55,000',
color: 'purple',
position: 4,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from55000To70000,
value: 'FROM_55000_TO_70000',
label: '55,000-70,000',
color: 'yellow',
position: 5,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from70000To85000,
value: 'FROM_70000_TO_85000',
label: '70,000-85,000',
color: 'pink',
position: 6,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from85000To100000,
value: 'FROM_85000_TO_100000',
label: '85,000-100,000',
color: 'cyan',
position: 7,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from100000To150000,
value: 'FROM_100000_TO_150000',
label: '100,000-150,000',
color: 'brown',
position: 8,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.from150000To250000,
value: 'FROM_150000_TO_250000',
label: '150,000-250,000',
color: 'lime',
position: 9,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personInferredSalary
.over250000,
value: 'OVER_250000',
label: '>250,000',
color: 'violet',
position: 10,
},
],
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlInterests,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.ARRAY,
name: 'pdlInterests',
label: 'Interests',
description: 'Interests returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobCompanyId,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlJobCompanyId',
label: 'Current Company PDL ID',
description: 'Current company PDL identifier returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,29 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { INDUSTRY_OPTIONS } from 'src/constants/industry-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobCompanyIndustry,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlJobCompanyIndustry',
label: 'Current Company Industry',
description:
'Current company canonical industry returned by People Data Labs.',
isNullable: true,
options: buildSelectOptions(
INDUSTRY_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobCompanyIndustry,
),
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobCompanyLinkedinUrl,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.LINKS,
name: 'pdlJobCompanyLinkedinUrl',
label: 'Current Company LinkedIn',
description: 'Current company LinkedIn returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobCompanyName,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlJobCompanyName',
label: 'Current Company',
description: 'Current company name returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,27 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { SIZE_OPTIONS } from 'src/constants/size-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobCompanySize,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlJobCompanySize',
label: 'Current Company Size',
description: 'Current company size range returned by People Data Labs.',
isNullable: true,
options: buildSelectOptions(
SIZE_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobCompanySize,
),
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobCompanyWebsite,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.LINKS,
name: 'pdlJobCompanyWebsite',
label: 'Current Company Website',
description: 'Current company website returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobHistory,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlJobHistory',
label: 'Job History',
description: 'Job history returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobOnetCode,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlJobOnetCode',
label: 'O*NET Code',
description: 'O*NET occupation code returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,191 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobRole,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlJobRole',
label: 'Job Role',
description: 'People Data Labs canonical job title role.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.advisory,
value: 'ADVISORY',
label: 'Advisory',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.analyst,
value: 'ANALYST',
label: 'Analyst',
color: 'red',
position: 1,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.creative,
value: 'CREATIVE',
label: 'Creative',
color: 'green',
position: 2,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.education,
value: 'EDUCATION',
label: 'Education',
color: 'orange',
position: 3,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.engineering,
value: 'ENGINEERING',
label: 'Engineering',
color: 'purple',
position: 4,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.finance,
value: 'FINANCE',
label: 'Finance',
color: 'yellow',
position: 5,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.fulfillment,
value: 'FULFILLMENT',
label: 'Fulfillment',
color: 'pink',
position: 6,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.health,
value: 'HEALTH',
label: 'Health',
color: 'cyan',
position: 7,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.hospitality,
value: 'HOSPITALITY',
label: 'Hospitality',
color: 'brown',
position: 8,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.humanResources,
value: 'HUMAN_RESOURCES',
label: 'Human Resources',
color: 'lime',
position: 9,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.legal,
value: 'LEGAL',
label: 'Legal',
color: 'violet',
position: 10,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.manufacturing,
value: 'MANUFACTURING',
label: 'Manufacturing',
color: 'gold',
position: 11,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.marketing,
value: 'MARKETING',
label: 'Marketing',
color: 'turquoise',
position: 12,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.operations,
value: 'OPERATIONS',
label: 'Operations',
color: 'crimson',
position: 13,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.partnerships,
value: 'PARTNERSHIPS',
label: 'Partnerships',
color: 'sky',
position: 14,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.product,
value: 'PRODUCT',
label: 'Product',
color: 'amber',
position: 15,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.professionalService,
value: 'PROFESSIONAL_SERVICE',
label: 'Professional Service',
color: 'plum',
position: 16,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.publicService,
value: 'PUBLIC_SERVICE',
label: 'Public Service',
color: 'grass',
position: 17,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.research,
value: 'RESEARCH',
label: 'Research',
color: 'tomato',
position: 18,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.sales,
value: 'SALES',
label: 'Sales',
color: 'iris',
position: 19,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.salesEngineering,
value: 'SALES_ENGINEERING',
label: 'Sales Engineering',
color: 'mint',
position: 20,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.support,
value: 'SUPPORT',
label: 'Support',
color: 'ruby',
position: 21,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.trade,
value: 'TRADE',
label: 'Trade',
color: 'bronze',
position: 22,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.jobRole.unemployed,
value: 'UNEMPLOYED',
label: 'Unemployed',
color: 'jade',
position: 23,
},
],
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobStartDate,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.DATE,
name: 'pdlJobStartDate',
label: 'Job Start Date',
description: 'Current job start date returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobSummary,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlJobSummary',
label: 'Job Summary',
description: 'Current job summary returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,61 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobTitleClass,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlJobTitleClass',
label: 'Job Class',
description: 'People Data Labs canonical job class.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobClass
.generalAndAdministrative,
value: 'GENERAL_AND_ADMINISTRATIVE',
label: 'General and Administrative',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobClass
.researchAndDevelopment,
value: 'RESEARCH_AND_DEVELOPMENT',
label: 'Research and Development',
color: 'red',
position: 1,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobClass
.salesAndMarketing,
value: 'SALES_AND_MARKETING',
label: 'Sales and Marketing',
color: 'green',
position: 2,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobClass.services,
value: 'SERVICES',
label: 'Services',
color: 'orange',
position: 3,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobClass.unemployed,
value: 'UNEMPLOYED',
label: 'Unemployed',
color: 'purple',
position: 4,
},
],
});
@@ -0,0 +1,803 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlJobTitleSubRole,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlJobTitleSubRole',
label: 'Job Sub-Role',
description: 'People Data Labs canonical job sub-role.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.academic,
value: 'ACADEMIC',
label: 'Academic',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.accountExecutive,
value: 'ACCOUNT_EXECUTIVE',
label: 'Account Executive',
color: 'red',
position: 1,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.accountManagement,
value: 'ACCOUNT_MANAGEMENT',
label: 'Account Management',
color: 'green',
position: 2,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.accounting,
value: 'ACCOUNTING',
label: 'Accounting',
color: 'orange',
position: 3,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.accountingServices,
value: 'ACCOUNTING_SERVICES',
label: 'Accounting Services',
color: 'purple',
position: 4,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.administrative,
value: 'ADMINISTRATIVE',
label: 'Administrative',
color: 'yellow',
position: 5,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.advisor,
value: 'ADVISOR',
label: 'Advisor',
color: 'pink',
position: 6,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.agriculture,
value: 'AGRICULTURE',
label: 'Agriculture',
color: 'cyan',
position: 7,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.aides,
value: 'AIDES',
label: 'Aides',
color: 'brown',
position: 8,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.architecture,
value: 'ARCHITECTURE',
label: 'Architecture',
color: 'lime',
position: 9,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.artist,
value: 'ARTIST',
label: 'Artist',
color: 'violet',
position: 10,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.boardMember,
value: 'BOARD_MEMBER',
label: 'Board Member',
color: 'gold',
position: 11,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.bookkeeping,
value: 'BOOKKEEPING',
label: 'Bookkeeping',
color: 'turquoise',
position: 12,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.brand,
value: 'BRAND',
label: 'Brand',
color: 'crimson',
position: 13,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.buildingAndGrounds,
value: 'BUILDING_AND_GROUNDS',
label: 'Building and Grounds',
color: 'sky',
position: 14,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.businessAnalyst,
value: 'BUSINESS_ANALYST',
label: 'Business Analyst',
color: 'amber',
position: 15,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.businessDevelopment,
value: 'BUSINESS_DEVELOPMENT',
label: 'Business Development',
color: 'plum',
position: 16,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.chemical,
value: 'CHEMICAL',
label: 'Chemical',
color: 'grass',
position: 17,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.compliance,
value: 'COMPLIANCE',
label: 'Compliance',
color: 'tomato',
position: 18,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.construction,
value: 'CONSTRUCTION',
label: 'Construction',
color: 'iris',
position: 19,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.consulting,
value: 'CONSULTING',
label: 'Consulting',
color: 'mint',
position: 20,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.content,
value: 'CONTENT',
label: 'Content',
color: 'ruby',
position: 21,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.corporateDevelopment,
value: 'CORPORATE_DEVELOPMENT',
label: 'Corporate Development',
color: 'bronze',
position: 22,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.curation,
value: 'CURATION',
label: 'Curation',
color: 'jade',
position: 23,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.customerSuccess,
value: 'CUSTOMER_SUCCESS',
label: 'Customer Success',
color: 'gray',
position: 24,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.customerSupport,
value: 'CUSTOMER_SUPPORT',
label: 'Customer Support',
color: 'blue',
position: 25,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.dataAnalyst,
value: 'DATA_ANALYST',
label: 'Data Analyst',
color: 'red',
position: 26,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.dataEngineering,
value: 'DATA_ENGINEERING',
label: 'Data Engineering',
color: 'green',
position: 27,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.dataScience,
value: 'DATA_SCIENCE',
label: 'Data Science',
color: 'orange',
position: 28,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.dental,
value: 'DENTAL',
label: 'Dental',
color: 'purple',
position: 29,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.devops,
value: 'DEVOPS',
label: 'DevOps',
color: 'yellow',
position: 30,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.doctor,
value: 'DOCTOR',
label: 'Doctor',
color: 'pink',
position: 31,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.electric,
value: 'ELECTRIC',
label: 'Electric',
color: 'cyan',
position: 32,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.electrical,
value: 'ELECTRICAL',
label: 'Electrical',
color: 'brown',
position: 33,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.emergencyServices,
value: 'EMERGENCY_SERVICES',
label: 'Emergency Services',
color: 'lime',
position: 34,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.entertainment,
value: 'ENTERTAINMENT',
label: 'Entertainment',
color: 'violet',
position: 35,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.executive,
value: 'EXECUTIVE',
label: 'Executive',
color: 'gold',
position: 36,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.fashion,
value: 'FASHION',
label: 'Fashion',
color: 'turquoise',
position: 37,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.financial,
value: 'FINANCIAL',
label: 'Financial',
color: 'crimson',
position: 38,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.fitness,
value: 'FITNESS',
label: 'Fitness',
color: 'sky',
position: 39,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.fraud,
value: 'FRAUD',
label: 'Fraud',
color: 'amber',
position: 40,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.graphicDesign,
value: 'GRAPHIC_DESIGN',
label: 'Graphic Design',
color: 'plum',
position: 41,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.growth,
value: 'GROWTH',
label: 'Growth',
color: 'grass',
position: 42,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.hairStylist,
value: 'HAIR_STYLIST',
label: 'Hair Stylist',
color: 'tomato',
position: 43,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.hardware,
value: 'HARDWARE',
label: 'Hardware',
color: 'iris',
position: 44,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.healthAndSafety,
value: 'HEALTH_AND_SAFETY',
label: 'Health and Safety',
color: 'mint',
position: 45,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.humanResources,
value: 'HUMAN_RESOURCES',
label: 'Human Resources',
color: 'ruby',
position: 46,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.implementation,
value: 'IMPLEMENTATION',
label: 'Implementation',
color: 'bronze',
position: 47,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.industrial,
value: 'INDUSTRIAL',
label: 'Industrial',
color: 'jade',
position: 48,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.informationTechnology,
value: 'INFORMATION_TECHNOLOGY',
label: 'Information Technology',
color: 'gray',
position: 49,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.insurance,
value: 'INSURANCE',
label: 'Insurance',
color: 'blue',
position: 50,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.investmentBanking,
value: 'INVESTMENT_BANKING',
label: 'Investment Banking',
color: 'red',
position: 51,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.investor,
value: 'INVESTOR',
label: 'Investor',
color: 'green',
position: 52,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.investorRelations,
value: 'INVESTOR_RELATIONS',
label: 'Investor Relations',
color: 'orange',
position: 53,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.journalism,
value: 'JOURNALISM',
label: 'Journalism',
color: 'purple',
position: 54,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.judicial,
value: 'JUDICIAL',
label: 'Judicial',
color: 'yellow',
position: 55,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.legal,
value: 'LEGAL',
label: 'Legal',
color: 'pink',
position: 56,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.legalServices,
value: 'LEGAL_SERVICES',
label: 'Legal Services',
color: 'cyan',
position: 57,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.logistics,
value: 'LOGISTICS',
label: 'Logistics',
color: 'brown',
position: 58,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.machinist,
value: 'MACHINIST',
label: 'Machinist',
color: 'lime',
position: 59,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.marketingDesign,
value: 'MARKETING_DESIGN',
label: 'Marketing Design',
color: 'violet',
position: 60,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.marketingServices,
value: 'MARKETING_SERVICES',
label: 'Marketing Services',
color: 'gold',
position: 61,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.mechanic,
value: 'MECHANIC',
label: 'Mechanic',
color: 'turquoise',
position: 62,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.mechanical,
value: 'MECHANICAL',
label: 'Mechanical',
color: 'crimson',
position: 63,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.military,
value: 'MILITARY',
label: 'Military',
color: 'sky',
position: 64,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.network,
value: 'NETWORK',
label: 'Network',
color: 'amber',
position: 65,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.nursing,
value: 'NURSING',
label: 'Nursing',
color: 'plum',
position: 66,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.partnerships,
value: 'PARTNERSHIPS',
label: 'Partnerships',
color: 'grass',
position: 67,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.pharmacy,
value: 'PHARMACY',
label: 'Pharmacy',
color: 'tomato',
position: 68,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.planningAndAnalysis,
value: 'PLANNING_AND_ANALYSIS',
label: 'Planning and Analysis',
color: 'iris',
position: 69,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.plumbing,
value: 'PLUMBING',
label: 'Plumbing',
color: 'mint',
position: 70,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.political,
value: 'POLITICAL',
label: 'Political',
color: 'ruby',
position: 71,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.primaryAndSecondary,
value: 'PRIMARY_AND_SECONDARY',
label: 'Primary and Secondary',
color: 'bronze',
position: 72,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.procurement,
value: 'PROCUREMENT',
label: 'Procurement',
color: 'jade',
position: 73,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.productDesign,
value: 'PRODUCT_DESIGN',
label: 'Product Design',
color: 'gray',
position: 74,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.productManagement,
value: 'PRODUCT_MANAGEMENT',
label: 'Product Management',
color: 'blue',
position: 75,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.professor,
value: 'PROFESSOR',
label: 'Professor',
color: 'red',
position: 76,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.projectManagement,
value: 'PROJECT_MANAGEMENT',
label: 'Project Management',
color: 'green',
position: 77,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.protectiveService,
value: 'PROTECTIVE_SERVICE',
label: 'Protective Service',
color: 'orange',
position: 78,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.qaEngineering,
value: 'QA_ENGINEERING',
label: 'QA Engineering',
color: 'purple',
position: 79,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.qualityAssurance,
value: 'QUALITY_ASSURANCE',
label: 'Quality Assurance',
color: 'yellow',
position: 80,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.realtor,
value: 'REALTOR',
label: 'Realtor',
color: 'pink',
position: 81,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.recruiting,
value: 'RECRUITING',
label: 'Recruiting',
color: 'cyan',
position: 82,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.restaurants,
value: 'RESTAURANTS',
label: 'Restaurants',
color: 'brown',
position: 83,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.retail,
value: 'RETAIL',
label: 'Retail',
color: 'lime',
position: 84,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.revenueOperations,
value: 'REVENUE_OPERATIONS',
label: 'Revenue Operations',
color: 'violet',
position: 85,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.risk,
value: 'RISK',
label: 'Risk',
color: 'gold',
position: 86,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.salesDevelopment,
value: 'SALES_DEVELOPMENT',
label: 'Sales Development',
color: 'turquoise',
position: 87,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.scientific,
value: 'SCIENTIFIC',
label: 'Scientific',
color: 'crimson',
position: 88,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.security,
value: 'SECURITY',
label: 'Security',
color: 'sky',
position: 89,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.socialService,
value: 'SOCIAL_SERVICE',
label: 'Social Service',
color: 'amber',
position: 90,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.software,
value: 'SOFTWARE',
label: 'Software',
color: 'plum',
position: 91,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.solutionsEngineer,
value: 'SOLUTIONS_ENGINEER',
label: 'Solutions Engineer',
color: 'grass',
position: 92,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.strategy,
value: 'STRATEGY',
label: 'Strategy',
color: 'tomato',
position: 93,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.student,
value: 'STUDENT',
label: 'Student',
color: 'iris',
position: 94,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.talentAnalytics,
value: 'TALENT_ANALYTICS',
label: 'Talent Analytics',
color: 'mint',
position: 95,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.therapy,
value: 'THERAPY',
label: 'Therapy',
color: 'ruby',
position: 96,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole
.tourAndTravel,
value: 'TOUR_AND_TRAVEL',
label: 'Tour and Travel',
color: 'bronze',
position: 97,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.training,
value: 'TRAINING',
label: 'Training',
color: 'jade',
position: 98,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.translation,
value: 'TRANSLATION',
label: 'Translation',
color: 'gray',
position: 99,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.transport,
value: 'TRANSPORT',
label: 'Transport',
color: 'blue',
position: 100,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.unemployed,
value: 'UNEMPLOYED',
label: 'Unemployed',
color: 'red',
position: 101,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.veterinarian,
value: 'VETERINARIAN',
label: 'Veterinarian',
color: 'green',
position: 102,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.warehouse,
value: 'WAREHOUSE',
label: 'Warehouse',
color: 'orange',
position: 103,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.web,
value: 'WEB',
label: 'Web',
color: 'purple',
position: 104,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personJobSubRole.wellness,
value: 'WELLNESS',
label: 'Wellness',
color: 'yellow',
position: 105,
},
],
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlLanguages,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlLanguages',
label: 'Languages',
description: 'Languages returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlLastEnrichedAt,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.DATE_TIME,
name: 'pdlLastEnrichedAt',
label: 'Last Enriched At',
description: 'Timestamp of the latest People Data Labs enrichment.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlLikelihood,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.NUMBER,
name: 'pdlLikelihood',
label: 'Match Likelihood',
description: 'People Data Labs match confidence score (1-10).',
isNullable: true,
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlLinkedinConnections,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.NUMBER,
name: 'pdlLinkedinConnections',
label: 'LinkedIn Connections',
description: 'LinkedIn connection count returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,19 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlLinkedinUsername,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlLinkedinUsername',
label: 'LinkedIn Username',
description: 'LinkedIn username returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,27 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { METRO_OPTIONS } from 'src/constants/metro-options';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
import { buildSelectOptions } from 'src/utils/build-select-options';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlLocationMetro,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlLocationMetro',
label: 'Metro Area',
description: 'People Data Labs canonical metro area.',
isNullable: true,
options: buildSelectOptions(
METRO_OPTIONS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.personLocationMetro,
),
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlLocation,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.ADDRESS,
name: 'pdlLocation',
label: 'Location',
description: 'Location returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlNameAliases,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.ARRAY,
name: 'pdlNameAliases',
label: 'Name Aliases',
description: 'Name aliases returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlProfiles,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlProfiles',
label: 'Social Profiles',
description: 'All social profiles returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlRawPayload,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.RAW_JSON,
name: 'pdlRawPayload',
label: 'PDL Raw Payload',
description: 'Full People Data Labs person enrichment response.',
isNullable: true,
});
@@ -0,0 +1,93 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlSeniority,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.MULTI_SELECT,
name: 'pdlSeniority',
label: 'Seniority',
description: 'People Data Labs canonical job title levels.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.cxo,
value: 'CXO',
label: 'CXO',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.owner,
value: 'OWNER',
label: 'Owner',
color: 'red',
position: 1,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.vp,
value: 'VP',
label: 'VP',
color: 'green',
position: 2,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.director,
value: 'DIRECTOR',
label: 'Director',
color: 'orange',
position: 3,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.partner,
value: 'PARTNER',
label: 'Partner',
color: 'purple',
position: 4,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.senior,
value: 'SENIOR',
label: 'Senior',
color: 'yellow',
position: 5,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.manager,
value: 'MANAGER',
label: 'Manager',
color: 'pink',
position: 6,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.entry,
value: 'ENTRY',
label: 'Entry',
color: 'cyan',
position: 7,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.training,
value: 'TRAINING',
label: 'Training',
color: 'brown',
position: 8,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.seniority.unpaid,
value: 'UNPAID',
label: 'Unpaid',
color: 'lime',
position: 9,
},
],
});
@@ -0,0 +1,37 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import {
PDL_FIELD_UNIVERSAL_IDENTIFIERS,
PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS,
} from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlSex,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.SELECT,
name: 'pdlSex',
label: 'Sex',
description: 'Sex returned by People Data Labs.',
isNullable: true,
options: [
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.sex.male,
value: 'MALE',
label: 'Male',
color: 'blue',
position: 0,
},
{
id: PDL_SELECT_OPTION_UNIVERSAL_IDENTIFIERS.sex.female,
value: 'FEMALE',
label: 'Female',
color: 'red',
position: 1,
},
],
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlSkills,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.ARRAY,
name: 'pdlSkills',
label: 'Skills',
description: 'Skills returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlSummary,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.TEXT,
name: 'pdlSummary',
label: 'Summary',
description: 'Profile summary returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlTwitterUrl,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.LINKS,
name: 'pdlTwitterUrl',
label: 'X / Twitter',
description: 'X or Twitter profile returned by People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,20 @@
import {
defineField,
FieldType,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineField({
universalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlYearsExperience,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
type: FieldType.NUMBER,
name: 'pdlYearsExperience',
label: 'Years of Experience',
description:
'Inferred years of professional experience from People Data Labs.',
isNullable: true,
});
@@ -0,0 +1,18 @@
import {
defineIndex,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineIndex({
universalIdentifier: 'b030537d-90e1-4b0a-9def-738ab78c36e0',
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
fields: [
{
universalIdentifier: 'b6875e91-f80e-4d6c-bbc1-9ea9217def09',
fieldUniversalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlId,
},
],
});
@@ -0,0 +1,19 @@
import {
defineIndex,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineIndex({
universalIdentifier: 'bf1c9130-33c7-4eea-b6f2-50333481c7cc',
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
fields: [
{
universalIdentifier: 'cb127127-0494-48a9-9784-395654e1d769',
fieldUniversalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlLastEnrichedAt,
},
],
});
@@ -0,0 +1,18 @@
import {
defineIndex,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineIndex({
universalIdentifier: '6ab8b38f-482c-46dc-a463-202fc4307b92',
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
fields: [
{
universalIdentifier: 'fd792806-29f1-44da-9199-f76d8219c6db',
fieldUniversalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlId,
},
],
});
@@ -0,0 +1,19 @@
import {
defineIndex,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { PDL_FIELD_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
export default defineIndex({
universalIdentifier: 'c71369f6-5ad3-4bb8-ade8-1c5597044ee7',
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
fields: [
{
universalIdentifier: '853c9e52-6aa8-499c-a41a-ed8dcf4b6247',
fieldUniversalIdentifier:
PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlLastEnrichedAt,
},
],
});
@@ -0,0 +1,39 @@
import {
defineApplicationRole,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
export default defineApplicationRole({
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
label: 'People Data Labs enrichment role',
description: 'Reads and updates People/Companies to write enrichment data.',
canReadAllObjectRecords: false,
canUpdateAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canDestroyAllObjectRecords: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: false,
canBeAssignedToApiKeys: false,
objectPermissions: [
{
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
canReadObjectRecords: true,
canUpdateObjectRecords: true,
canSoftDeleteObjectRecords: false,
canDestroyObjectRecords: false,
},
{
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
canReadObjectRecords: true,
canUpdateObjectRecords: true,
canSoftDeleteObjectRecords: false,
canDestroyObjectRecords: false,
},
],
fieldPermissions: [],
});
@@ -0,0 +1,9 @@
import { type TagColor } from 'src/types/tag-color.type';
export type SelectOptionMeta = {
key: string;
value: string;
label: string;
color: TagColor;
position: number;
};

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