Files
twenty/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts
T
Charles Bochet 96fc98e710 Fix Apps UI: replace 'Managed' label with actual app name and unify app icons (#19897)
## Summary

- The Data Model table was labeling core Twenty objects (e.g. Person,
Company) as **Managed** even though they are part of the standard
application. This PR teaches the frontend to resolve an `applicationId`
back to its real application name (`Standard`, `Custom`, or any
installed app), and removes the misleading **Managed** label entirely.
- Introduces a single, consistent way to render an "app badge" across
the settings UI:
- new `Avatar` variant `type="app"` (rounded 4px corners + 1px
deterministic border derived from `placeholderColorSeed`)
- new `AppChip` component (icon + name) backed by a new
`useApplicationChipData` hook
- new `useApplicationsByIdMap` hook + `CurrentApplicationContext` so the
chip can render **This app** when shown inside the matching app's detail
page
- Reuses these primitives on:
- the application detail page header (`SettingsApplicationDetailTitle`)
  - the Installed / My apps tables (`SettingsApplicationTableRow`)
  - the NPM packages list (`SettingsApplicationsDeveloperTab`)
- Backend: exposes a minimal `installedApplications { id name
universalIdentifier }` field on `Workspace` (resolved from the workspace
cache, soft-deleted entries filtered out) so the frontend can resolve
`applicationId` -> name without N+1 fetches.
- Cleanup: deletes `getItemTagInfo` and inlines its tiny
responsibilities into the components that need them, matching the
`RecordChip` pattern.
2026-04-21 00:44:14 +02:00

58 lines
1.5 KiB
TypeScript

import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
import {
type Application,
type Role,
type Workspace,
} from '~/generated-metadata/graphql';
export type CurrentWorkspace = Pick<
Workspace,
| 'id'
| 'inviteHash'
| 'logo'
| 'displayName'
| 'allowImpersonation'
| 'featureFlags'
| 'activationStatus'
| 'billingSubscriptions'
| 'billingEntitlements'
| 'currentBillingSubscription'
| 'workspaceMembersCount'
| 'isPublicInviteLinkEnabled'
| 'isGoogleAuthEnabled'
| 'isGoogleAuthBypassEnabled'
| 'isMicrosoftAuthEnabled'
| 'isMicrosoftAuthBypassEnabled'
| 'isPasswordAuthEnabled'
| 'isPasswordAuthBypassEnabled'
| 'isCustomDomainEnabled'
| 'hasValidEnterpriseKey'
| 'hasValidSignedEnterpriseKey'
| 'hasValidEnterpriseValidityToken'
| 'subdomain'
| 'customDomain'
| 'workspaceUrls'
| 'metadataVersion'
| 'isTwoFactorAuthenticationEnforced'
| 'trashRetentionDays'
| 'eventLogRetentionDays'
| 'fastModel'
| 'smartModel'
| 'aiAdditionalInstructions'
| 'editableProfileFields'
| 'enabledAiModelIds'
| 'useRecommendedModels'
> & {
defaultRole?: Omit<Role, 'workspaceMembers' | 'agents' | 'apiKeys'> | null;
workspaceCustomApplication: Pick<Application, 'id'> | null;
installedApplications: Pick<
Application,
'id' | 'name' | 'universalIdentifier'
>[];
};
export const currentWorkspaceState = createAtomState<CurrentWorkspace | null>({
key: 'currentWorkspaceState',
defaultValue: null,
});