chore: remove noisy comments, keep only essential ones
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
c15ae95c5f
commit
fa59e96762
+1
-4
@@ -1,5 +1,2 @@
|
||||
// Maximum total recipients (To + Cc + Bcc) allowed per outbound email.
|
||||
// Mirrors `MAX_EMAIL_RECIPIENTS` in twenty-server (email-tool.constants.ts).
|
||||
// Surfaced on the frontend so the composer can disable Send and warn the user
|
||||
// before the request is rejected by the backend.
|
||||
// Mirrors MAX_EMAIL_RECIPIENTS in twenty-server (email-tool.constants.ts).
|
||||
export const MAX_EMAIL_RECIPIENTS = 100;
|
||||
|
||||
-3
@@ -6,9 +6,6 @@ import { SettingsPath } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||
|
||||
// Wires the compose-email side panel to the record currently shown in the
|
||||
// page (Person, Company or Opportunity). Used by both the inbox header `+`
|
||||
// button and the empty-inbox CTA so they stay in sync.
|
||||
export const useComposeEmailForTargetRecord = () => {
|
||||
const targetRecord = useTargetRecord();
|
||||
const { openComposeEmailInSidePanel } = useOpenComposeEmailInSidePanel();
|
||||
|
||||
@@ -12,9 +12,6 @@ type UseEmailComposerStateArgs = {
|
||||
onSent?: () => void;
|
||||
};
|
||||
|
||||
// Light-weight count of comma-separated recipients. Mirrors the backend
|
||||
// `parseCommaSeparatedEmails` splitter so the disabled state matches what the
|
||||
// server would actually accept — we just count, no validation.
|
||||
const countRecipients = (csv: string): number =>
|
||||
csv
|
||||
.split(',')
|
||||
|
||||
+2
-7
@@ -5,16 +5,11 @@ import { useOpenComposeEmailInSidePanel } from '@/side-panel/hooks/useOpenCompos
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type UseOpenEmailInAppOrFallbackOptions = {
|
||||
// When true the underlying connected-account query is skipped entirely,
|
||||
// avoiding an unnecessary network request for non-email field types or when
|
||||
// the click action is not OPEN_IN_APP.
|
||||
skip?: boolean;
|
||||
};
|
||||
|
||||
// Opens the in-app email composer for the given email address. When the user
|
||||
// has no connected account we cannot send through the side panel, so we fall
|
||||
// back to the OS-level mailto handler instead of redirecting to settings —
|
||||
// the user explicitly opted into "Open in app" and the link is still useful.
|
||||
// Falls back to mailto: when no connected account exists, rather than
|
||||
// redirecting to settings.
|
||||
export const useOpenEmailInAppOrFallback = (
|
||||
options?: UseOpenEmailInAppOrFallbackOptions,
|
||||
) => {
|
||||
|
||||
-5
@@ -7,11 +7,6 @@ type UseResolveDefaultEmailRecipientParams = {
|
||||
recordId: string | null | undefined;
|
||||
};
|
||||
|
||||
// Resolves the default `to` email recipient for a record so that the email
|
||||
// composer can be opened pre-filled. The recipient depends on the object type:
|
||||
// - person: the person's primary email
|
||||
// - company: the primary email of the first person attached to the company
|
||||
// - opportunity: the primary email of the opportunity's point of contact
|
||||
export const useResolveDefaultEmailRecipient = ({
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
|
||||
@@ -12,10 +12,6 @@ import { formatFileSize } from '@/file/utils/formatFileSize';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { logError } from '~/utils/logError';
|
||||
|
||||
// Email attachment uploads return the same `FileWithSignedUrlDTO` shape as
|
||||
// every other typed upload mutation; we declare it locally to avoid depending
|
||||
// on a codegen-generated document for this mutation (see comment in
|
||||
// uploadEmailAttachmentFile.ts).
|
||||
type UploadEmailAttachmentFileResponse = {
|
||||
uploadEmailAttachmentFile: {
|
||||
id: string;
|
||||
@@ -38,10 +34,6 @@ export const useUploadEmailAttachment = () => {
|
||||
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
|
||||
const { t } = useLingui();
|
||||
|
||||
// We reuse `WorkflowAttachment` as the in-memory shape because the SendEmail
|
||||
// mutation input mirrors it field-for-field — sharing the type keeps the
|
||||
// composer wiring trivial. The persisted file lives under the
|
||||
// `email-attachment` folder, not the workflow folder.
|
||||
const uploadEmailAttachment = async (
|
||||
file: File,
|
||||
): Promise<WorkflowAttachment | null> => {
|
||||
|
||||
@@ -2,10 +2,6 @@ import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
// Reads `record.emails.primaryEmail` defensively. `ObjectRecord` is typed as
|
||||
// `Record<string, any>` so accessing nested fields is unchecked at compile
|
||||
// time — we narrow at runtime so callers can rely on a `string | null` result
|
||||
// without sprinkling `as` casts at every call site.
|
||||
export const getPrimaryEmailFromRecord = (
|
||||
record: ObjectRecord,
|
||||
): string | null => {
|
||||
|
||||
-9
@@ -26,17 +26,10 @@ export const ComposeEmailCommand = () => {
|
||||
const objectNameSingular = objectMetadataItem?.nameSingular ?? null;
|
||||
const isPerson = objectNameSingular === CoreObjectNameSingular.Person;
|
||||
|
||||
// Bulk means more than one record is selected *or* the user is in
|
||||
// exclusion/"select all" mode where selectedRecords is empty but the
|
||||
// graphqlFilter encodes the full target set.
|
||||
const isBulkPerson =
|
||||
isPerson &&
|
||||
(selectedRecords.length > 1 || targetedRecordsRule.mode === 'exclusion');
|
||||
|
||||
// For bulk Person selections we fetch emails directly from the server so
|
||||
// we always have the data regardless of which columns are visible in the
|
||||
// current view. Capped at MAX_EMAIL_RECIPIENTS since the backend will
|
||||
// reject anything above that anyway.
|
||||
const { records: bulkPersonRecords, loading: bulkLoading } =
|
||||
useFindManyRecords({
|
||||
objectNameSingular: CoreObjectNameSingular.Person,
|
||||
@@ -46,8 +39,6 @@ export const ComposeEmailCommand = () => {
|
||||
skip: !isBulkPerson,
|
||||
});
|
||||
|
||||
// For single-record selection we use the shared resolver which handles
|
||||
// the per-object-type fetching (Person, Company, Opportunity).
|
||||
const singleSelectedRecordId = !isBulkPerson
|
||||
? (selectedRecords[0]?.id ?? null)
|
||||
: null;
|
||||
|
||||
-6
@@ -11,9 +11,6 @@ export const EmailsFieldDisplay = () => {
|
||||
const { copyToClipboard } = useCopyToClipboard();
|
||||
const { t } = useLingui();
|
||||
|
||||
// Email fields default to opening the in-app composer when no setting is
|
||||
// explicitly stored. The mailto-based <a> stays as the rendered href so the
|
||||
// link is still right-clickable / openable in a new tab.
|
||||
const onClickAction =
|
||||
fieldDefinition.metadata.settings?.clickAction ??
|
||||
FieldMetadataSettingsOnClickAction.OPEN_IN_APP;
|
||||
@@ -21,8 +18,6 @@ export const EmailsFieldDisplay = () => {
|
||||
const isOpenInApp =
|
||||
onClickAction === FieldMetadataSettingsOnClickAction.OPEN_IN_APP;
|
||||
|
||||
// Only fire the connected-account query when the click action is
|
||||
// OPEN_IN_APP — COPY and OPEN_LINK don't need it.
|
||||
const { openEmail } = useOpenEmailInAppOrFallback({ skip: !isOpenInApp });
|
||||
|
||||
const handleEmailClick = (
|
||||
@@ -43,7 +38,6 @@ export const EmailsFieldDisplay = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// OPEN_LINK: let the native <a href="mailto:…"> behaviour handle it.
|
||||
};
|
||||
|
||||
return <EmailsDisplay value={fieldValue} onEmailClick={handleEmailClick} />;
|
||||
|
||||
-7
@@ -22,8 +22,6 @@ export const useGetSecondaryRecordTableCellButton = () => {
|
||||
|
||||
const isEmailField = isFieldEmails(fieldDefinition);
|
||||
|
||||
// Only fire the connected-account query for email fields — phone and link
|
||||
// fields never use the in-app composer so the request would be wasted.
|
||||
const { openEmail } = useOpenEmailInAppOrFallback({ skip: !isEmailField });
|
||||
|
||||
const fieldValue = useRecordFieldValue<
|
||||
@@ -39,8 +37,6 @@ export const useGetSecondaryRecordTableCellButton = () => {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Email fields default to opening the in-app composer; other field types
|
||||
// default to opening the platform link handler.
|
||||
const defaultClickAction = isEmailField
|
||||
? FieldMetadataSettingsOnClickAction.OPEN_IN_APP
|
||||
: FieldMetadataSettingsOnClickAction.OPEN_LINK;
|
||||
@@ -48,9 +44,6 @@ export const useGetSecondaryRecordTableCellButton = () => {
|
||||
const mainActionOnClick =
|
||||
fieldDefinition.metadata.settings?.clickAction ?? defaultClickAction;
|
||||
|
||||
// The secondary button always exposes the "other" useful action: if main is
|
||||
// a copy then offer an open action, otherwise offer copy. For emails the
|
||||
// open action is the in-app composer rather than mailto.
|
||||
const openActionForFieldType = isEmailField
|
||||
? FieldMetadataSettingsOnClickAction.OPEN_IN_APP
|
||||
: FieldMetadataSettingsOnClickAction.OPEN_LINK;
|
||||
|
||||
-2
@@ -37,8 +37,6 @@ export const SettingsDataModelFieldOnClickActionForm = ({
|
||||
|
||||
const isEmailField = fieldType === FieldMetadataType.EMAILS;
|
||||
|
||||
// For email fields we offer (and default to) opening the in-app composer.
|
||||
// Other field types keep "Open as link" as the default.
|
||||
const defaultClickAction = isEmailField
|
||||
? FieldMetadataSettingsOnClickAction.OPEN_IN_APP
|
||||
: FieldMetadataSettingsOnClickAction.OPEN_LINK;
|
||||
|
||||
-3
@@ -45,9 +45,6 @@ export class FileEmailAttachmentService {
|
||||
},
|
||||
);
|
||||
|
||||
// Email attachments are transient: once the email is sent, the local
|
||||
// copy is no longer needed for retrieval. Mark as temporary so the
|
||||
// file deletion job can sweep it.
|
||||
const savedFile = await this.fileStorageService.writeFile({
|
||||
sourceFile: sanitizedFile,
|
||||
resourcePath: name,
|
||||
|
||||
-2
@@ -1,3 +1 @@
|
||||
// Maximum total recipients (To + Cc + Bcc) allowed per outbound email.
|
||||
// Mirrored on the frontend in MAX_EMAIL_RECIPIENTS to provide early UX feedback.
|
||||
export const MAX_EMAIL_RECIPIENTS = 100;
|
||||
|
||||
-5
@@ -943,11 +943,6 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
hotKeys: null,
|
||||
payload: { path: '/settings/updates' },
|
||||
},
|
||||
// Per-object Send Email items: same engine component as the global
|
||||
// Compose Email command, but scoped to a record selection so the composer
|
||||
// can be opened pre-filled with the selected record's email address.
|
||||
// Person allows >= 1 so it works both from a record show page and from a
|
||||
// bulk selection on the people index page.
|
||||
composeEmailToPerson: {
|
||||
universalIdentifier: 'f01d4b8b-2b4e-4ae0-9c6f-0b9a9a3e5b21',
|
||||
label: 'Send Email',
|
||||
|
||||
+1
-5
@@ -1,10 +1,6 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
// Mirrors the `WorkflowAttachment` shape from twenty-shared (id/name/size/type/
|
||||
// createdAt). Inlined as a GraphQL input so the side-panel composer can pass
|
||||
// already-uploaded files without depending on workflow types. If you change
|
||||
// either side, keep both in sync — `EmailComposerService.getAttachments`
|
||||
// resolves files by id, so the field names matter.
|
||||
// Must stay in sync with WorkflowAttachment from twenty-shared.
|
||||
@InputType()
|
||||
export class SendEmailAttachmentInput {
|
||||
@Field(() => String)
|
||||
|
||||
Reference in New Issue
Block a user