File - Migrate core pictures (workspace and member logo) + workflow attachments (#17924)
- Create a common file-by-id download controller - Create core picture module with resolver and logic to handle workspaceLogo and workspaceMemberProfilePicture update - Create workflow file module (same) - Data migration
This commit is contained in:
+3
-3
@@ -1,14 +1,14 @@
|
||||
import { getFileType } from '@/activities/files/utils/getFileType';
|
||||
import { IconMapping } from '@/file/utils/fileIconMappings';
|
||||
import { useFileCategoryColors } from '@/file/hooks/useFileCategoryColors';
|
||||
import { type WorkflowAttachmentType } from '@/workflow/workflow-steps/workflow-actions/email-action/types/WorkflowAttachmentType';
|
||||
import { IconMapping } from '@/file/utils/fileIconMappings';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { type WorkflowAttachment } from 'twenty-shared/workflow';
|
||||
import { AvatarChip } from 'twenty-ui/components';
|
||||
import { IconX } from 'twenty-ui/display';
|
||||
|
||||
type WorkflowAttachmentChipProps = {
|
||||
file: WorkflowAttachmentType;
|
||||
file: WorkflowAttachment;
|
||||
onRemove: () => void;
|
||||
readonly?: boolean;
|
||||
};
|
||||
|
||||
+7
-9
@@ -1,18 +1,18 @@
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { WorkflowAttachmentChip } from '@/advanced-text-editor/components/WorkflowAttachmentChip';
|
||||
import { useUploadWorkflowFile } from '@/advanced-text-editor/hooks/useUploadWorkflowFile';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
|
||||
import { type WorkflowAttachmentType } from '@/workflow/workflow-steps/workflow-actions/email-action/types/WorkflowAttachmentType';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { type ChangeEvent, useRef } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type WorkflowAttachment } from 'twenty-shared/workflow';
|
||||
import { IconUpload } from 'twenty-ui/display';
|
||||
import { useTheme } from '@emotion/react';
|
||||
|
||||
type WorkflowSendEmailAttachmentsProps = {
|
||||
files: WorkflowAttachmentType[];
|
||||
onChange: (files: WorkflowAttachmentType[]) => void;
|
||||
files: WorkflowAttachment[];
|
||||
onChange: (files: WorkflowAttachment[]) => void;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
@@ -92,9 +92,7 @@ export const WorkflowSendEmailAttachments = ({
|
||||
filesToUpload.map((file) => uploadWorkflowFile(file)),
|
||||
);
|
||||
|
||||
const successfulUploads = uploadedFiles.filter(
|
||||
(file): file is WorkflowAttachmentType => file !== null,
|
||||
);
|
||||
const successfulUploads = uploadedFiles.filter(isDefined);
|
||||
|
||||
if (successfulUploads.length > 0) {
|
||||
onChange([...files, ...successfulUploads]);
|
||||
@@ -132,7 +130,7 @@ export const WorkflowSendEmailAttachments = ({
|
||||
>
|
||||
{files.length > 0 ? (
|
||||
<StyledChipsContainer>
|
||||
{files.map((file: WorkflowAttachmentType) => (
|
||||
{files.map((file: WorkflowAttachment) => (
|
||||
<WorkflowAttachmentChip
|
||||
key={file.id}
|
||||
file={file}
|
||||
|
||||
+47
-31
@@ -1,31 +1,33 @@
|
||||
import { MAX_ATTACHMENT_SIZE } from '@/advanced-text-editor/utils/MaxAttachmentSize';
|
||||
import { formatFileSize } from '@/file/utils/formatFileSize';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractFolderPathFilenameAndTypeOrThrow,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
import { useCreateFileMutation } from '~/generated-metadata/graphql';
|
||||
import { type WorkflowAttachment } from 'twenty-shared/workflow';
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
useCreateFileMutation,
|
||||
useUploadWorkflowFileMutation,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { logError } from '~/utils/logError';
|
||||
|
||||
type WorkflowFile = {
|
||||
id: string;
|
||||
name: string;
|
||||
size: number;
|
||||
type: string;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
export const useUploadWorkflowFile = () => {
|
||||
const coreClient = useApolloCoreClient();
|
||||
const [createFile] = useCreateFileMutation({ client: coreClient });
|
||||
const isOtherFileMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_OTHER_FILE_MIGRATED,
|
||||
);
|
||||
const [uploadWorkflowFileMutation] = useUploadWorkflowFileMutation();
|
||||
const apolloClient = useApolloClient();
|
||||
const [createFile] = useCreateFileMutation({ client: apolloClient });
|
||||
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
|
||||
|
||||
const uploadWorkflowFile = async (
|
||||
file: File,
|
||||
): Promise<WorkflowFile | null> => {
|
||||
): Promise<WorkflowAttachment | null> => {
|
||||
try {
|
||||
if (file.size > MAX_ATTACHMENT_SIZE) {
|
||||
const fileName = file.name;
|
||||
@@ -36,28 +38,42 @@ export const useUploadWorkflowFile = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = await createFile({
|
||||
variables: { file },
|
||||
});
|
||||
let workflowFile: WorkflowAttachment;
|
||||
if (isOtherFileMigrated) {
|
||||
const result = await uploadWorkflowFileMutation({
|
||||
variables: { file },
|
||||
});
|
||||
const uploadedFile = result?.data?.uploadWorkflowFile;
|
||||
if (!isDefined(uploadedFile)) {
|
||||
throw new Error('File upload failed');
|
||||
}
|
||||
workflowFile = {
|
||||
id: uploadedFile.id,
|
||||
name: file.name,
|
||||
size: uploadedFile.size,
|
||||
type: extractFolderPathFilenameAndTypeOrThrow(uploadedFile.path).type,
|
||||
createdAt: uploadedFile.createdAt,
|
||||
};
|
||||
} else {
|
||||
const result = await createFile({
|
||||
variables: { file },
|
||||
});
|
||||
|
||||
const uploadedFile = result?.data?.createFile;
|
||||
const uploadedFile = result?.data?.createFile;
|
||||
|
||||
if (!isDefined(uploadedFile)) {
|
||||
throw new Error('File upload failed');
|
||||
if (!isDefined(uploadedFile)) {
|
||||
throw new Error('File upload failed');
|
||||
}
|
||||
|
||||
workflowFile = {
|
||||
id: uploadedFile.id,
|
||||
name: file.name,
|
||||
size: uploadedFile.size,
|
||||
type: extractFolderPathFilenameAndTypeOrThrow(uploadedFile.path).type,
|
||||
createdAt: uploadedFile.createdAt,
|
||||
};
|
||||
}
|
||||
|
||||
const { type } = extractFolderPathFilenameAndTypeOrThrow(
|
||||
uploadedFile.path,
|
||||
);
|
||||
|
||||
const workflowFile: WorkflowFile = {
|
||||
id: uploadedFile.id,
|
||||
name: file.name,
|
||||
size: uploadedFile.size,
|
||||
type: type,
|
||||
createdAt: uploadedFile.createdAt,
|
||||
};
|
||||
|
||||
const fileName = file.name;
|
||||
enqueueSuccessSnackBar({
|
||||
message: t`File "${fileName}" uploaded successfully`,
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPLOAD_WORKFLOW_FILE = gql`
|
||||
mutation UploadWorkflowFile($file: Upload!) {
|
||||
uploadWorkflowFile(file: $file) {
|
||||
id
|
||||
path
|
||||
size
|
||||
createdAt
|
||||
url
|
||||
}
|
||||
}
|
||||
`;
|
||||
+1
-2
@@ -3,8 +3,7 @@ import { gql } from '@apollo/client';
|
||||
export const UPLOAD_WORKSPACE_MEMBER_PROFILE_PICTURE = gql`
|
||||
mutation UploadWorkspaceMemberProfilePicture($file: Upload!) {
|
||||
uploadWorkspaceMemberProfilePicture(file: $file) {
|
||||
path
|
||||
token
|
||||
url
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPLOAD_WORKSPACE_MEMBER_PROFILE_PICTURE_LEGACY = gql`
|
||||
mutation UploadWorkspaceMemberProfilePictureLegacy($file: Upload!) {
|
||||
uploadWorkspaceMemberProfilePictureLegacy(file: $file) {
|
||||
path
|
||||
token
|
||||
}
|
||||
}
|
||||
`;
|
||||
+55
-21
@@ -5,12 +5,16 @@ import { useRecoilState } from 'recoil';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { UPLOAD_WORKSPACE_MEMBER_PROFILE_PICTURE } from '@/settings/members/graphql/mutations/uploadWorkspaceMemberProfilePicture';
|
||||
import { useCanEditProfileField } from '@/settings/profile/hooks/useCanEditProfileField';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { ImageInput } from '@/ui/input/components/ImageInput';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { buildSignedPath, isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
useUploadWorkspaceMemberProfilePictureLegacyMutation,
|
||||
useUploadWorkspaceMemberProfilePictureMutation,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
type WorkspaceMemberPictureUploaderProps = {
|
||||
@@ -26,6 +30,9 @@ export const WorkspaceMemberPictureUploader = ({
|
||||
onAvatarUpdated,
|
||||
disabled = false,
|
||||
}: WorkspaceMemberPictureUploaderProps) => {
|
||||
const isCorePictureMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_CORE_PICTURE_MIGRATED,
|
||||
);
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
@@ -36,7 +43,9 @@ export const WorkspaceMemberPictureUploader = ({
|
||||
currentWorkspaceMemberState,
|
||||
);
|
||||
|
||||
const [uploadPicture] = useMutation(UPLOAD_WORKSPACE_MEMBER_PROFILE_PICTURE);
|
||||
const [uploadPicture] = useUploadWorkspaceMemberProfilePictureMutation();
|
||||
const [uploadPictureLegacy] =
|
||||
useUploadWorkspaceMemberProfilePictureLegacyMutation();
|
||||
|
||||
const { updateOneRecord } = useUpdateOneRecord();
|
||||
|
||||
@@ -56,29 +65,54 @@ export const WorkspaceMemberPictureUploader = ({
|
||||
setIsUploading(true);
|
||||
setErrorMessage(null);
|
||||
|
||||
let newAvatarUrl: string | null = null;
|
||||
try {
|
||||
const { data } = await uploadPicture({
|
||||
variables: { file },
|
||||
context: {
|
||||
fetchOptions: {
|
||||
signal: controller.signal,
|
||||
if (!isCorePictureMigrated) {
|
||||
const { data } = await uploadPictureLegacy({
|
||||
variables: { file },
|
||||
context: {
|
||||
fetchOptions: {
|
||||
signal: controller.signal,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const signedFile = data?.uploadWorkspaceMemberProfilePicture;
|
||||
if (!isDefined(signedFile)) {
|
||||
throw new Error('Avatar upload failed');
|
||||
const signedFile = data?.uploadWorkspaceMemberProfilePictureLegacy;
|
||||
if (!isDefined(signedFile)) {
|
||||
throw new Error('Avatar upload failed');
|
||||
}
|
||||
|
||||
await updateOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||
idToUpdate: workspaceMemberId,
|
||||
updateOneRecordInput: { avatarUrl: signedFile.path },
|
||||
});
|
||||
|
||||
newAvatarUrl = buildSignedPath(signedFile);
|
||||
} else {
|
||||
const { data } = await uploadPicture({
|
||||
variables: { file },
|
||||
context: {
|
||||
fetchOptions: {
|
||||
signal: controller.signal,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const signedFile = data?.uploadWorkspaceMemberProfilePicture;
|
||||
if (!isDefined(signedFile)) {
|
||||
throw new Error('Avatar upload failed');
|
||||
}
|
||||
|
||||
await updateOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||
idToUpdate: workspaceMemberId,
|
||||
updateOneRecordInput: { avatarUrl: signedFile.url },
|
||||
});
|
||||
|
||||
newAvatarUrl = signedFile.url;
|
||||
}
|
||||
|
||||
await updateOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||
idToUpdate: workspaceMemberId,
|
||||
updateOneRecordInput: { avatarUrl: signedFile.path },
|
||||
});
|
||||
|
||||
const newAvatarUrl = buildSignedPath(signedFile);
|
||||
|
||||
if (isEditingSelf && isDefined(currentWorkspaceMember)) {
|
||||
setCurrentWorkspaceMember({
|
||||
...currentWorkspaceMember,
|
||||
|
||||
+34
-12
@@ -2,14 +2,21 @@ import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { ImageInput } from '@/ui/input/components/ImageInput';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
useUpdateWorkspaceMutation,
|
||||
useUploadWorkspaceLogoLegacyMutation,
|
||||
useUploadWorkspaceLogoMutation,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
|
||||
export const WorkspaceLogoUploader = () => {
|
||||
const isCorePictureMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_CORE_PICTURE_MIGRATED,
|
||||
);
|
||||
const [uploadLogoLegacy] = useUploadWorkspaceLogoLegacyMutation();
|
||||
const [uploadLogo] = useUploadWorkspaceLogoMutation();
|
||||
const [updateWorkspace] = useUpdateWorkspaceMutation();
|
||||
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
|
||||
@@ -23,17 +30,32 @@ export const WorkspaceLogoUploader = () => {
|
||||
if (!currentWorkspace?.id) {
|
||||
throw new Error('Workspace id not found');
|
||||
}
|
||||
await uploadLogo({
|
||||
variables: {
|
||||
file,
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
setCurrentWorkspace({
|
||||
...currentWorkspace,
|
||||
logo: buildSignedPath(data.uploadWorkspaceLogo),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
if (isCorePictureMigrated) {
|
||||
await uploadLogo({
|
||||
variables: {
|
||||
file,
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
setCurrentWorkspace({
|
||||
...currentWorkspace,
|
||||
logo: data.uploadWorkspaceLogo.url,
|
||||
});
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await uploadLogoLegacy({
|
||||
variables: {
|
||||
file,
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
setCurrentWorkspace({
|
||||
...currentWorkspace,
|
||||
logo: buildSignedPath(data.uploadWorkspaceLogoLegacy),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onRemove = async () => {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import {
|
||||
type EmailRecipients,
|
||||
type WorkflowAttachment,
|
||||
} from 'twenty-shared/workflow';
|
||||
|
||||
export type EmailFormData = {
|
||||
connectedAccountId: string;
|
||||
recipients: Required<EmailRecipients>;
|
||||
subject: string;
|
||||
body: string;
|
||||
files: WorkflowAttachment[];
|
||||
};
|
||||
@@ -120,7 +120,6 @@ export type WorkflowVersionStatus =
|
||||
| 'DEACTIVATED'
|
||||
| 'ARCHIVED';
|
||||
|
||||
// Keep existing types that are not covered by schemas
|
||||
export type WorkflowVersion = {
|
||||
id: string;
|
||||
name: string;
|
||||
|
||||
+1
-1
@@ -2,8 +2,8 @@ import {
|
||||
type WorkflowStep,
|
||||
type WorkflowTrigger,
|
||||
} from '@/workflow/types/Workflow';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { StepStatus, type WorkflowRunStepInfos } from 'twenty-shared/workflow';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { getUuidV4Mock } from '~/testing/utils/getUuidV4Mock';
|
||||
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
|
||||
|
||||
|
||||
+4
-4
@@ -1,12 +1,12 @@
|
||||
import { type WorkflowRunFlow } from '@/workflow/types/Workflow';
|
||||
import { type WorkflowRunStepContext } from '@/workflow/workflow-steps/types/WorkflowRunStepContext';
|
||||
import { getPreviousSteps } from '@/workflow/workflow-steps/utils/getWorkflowPreviousSteps';
|
||||
import { getWorkflowRunAllStepInfoHistory } from '@/workflow/workflow-steps/utils/getWorkflowRunAllStepInfoHistory';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
TRIGGER_STEP_ID,
|
||||
type WorkflowRunStepInfos,
|
||||
} from 'twenty-shared/workflow';
|
||||
import { type WorkflowRunStepContext } from '@/workflow/workflow-steps/types/WorkflowRunStepContext';
|
||||
import { getPreviousSteps } from '@/workflow/workflow-steps/utils/getWorkflowPreviousSteps';
|
||||
import { getWorkflowRunAllStepInfoHistory } from '@/workflow/workflow-steps/utils/getWorkflowRunAllStepInfoHistory';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getWorkflowRunStepContext = ({
|
||||
stepId,
|
||||
|
||||
+1
-1
@@ -22,7 +22,6 @@ import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithC
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter';
|
||||
import { type WorkflowEmailAction } from '@/workflow/workflow-steps/workflow-actions/email-action/types/WorkflowEmailAction';
|
||||
import { useEmailForm } from '@/workflow/workflow-steps/workflow-actions/hooks/useEmailForm';
|
||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||
import { useTheme } from '@emotion/react';
|
||||
@@ -31,6 +30,7 @@ import { useEffect, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { ConnectedAccountProvider, SettingsPath } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type WorkflowEmailAction } from '@/workflow/types/WorkflowEmailAction';
|
||||
import { Callout, IconPlus } from 'twenty-ui/display';
|
||||
import { Button, type SelectOption } from 'twenty-ui/input';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
|
||||
+1
-1
@@ -1,4 +1,3 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition';
|
||||
import { FormFieldInput } from '@/object-record/record-field/ui/components/FormFieldInput';
|
||||
@@ -14,6 +13,7 @@ import { type UpdateRecordFormData } from '@/workflow/workflow-steps/workflow-ac
|
||||
import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField';
|
||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { canObjectBeManagedByWorkflow } from 'twenty-shared/workflow';
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
import { type WorkflowAttachmentType } from '@/workflow/workflow-steps/workflow-actions/email-action/types/WorkflowAttachmentType';
|
||||
import { type EmailRecipients } from 'twenty-shared/workflow';
|
||||
|
||||
export type EmailFormData = {
|
||||
connectedAccountId: string;
|
||||
recipients: Required<EmailRecipients>;
|
||||
subject: string;
|
||||
body: string;
|
||||
files: WorkflowAttachmentType[];
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
export type WorkflowAttachmentType = {
|
||||
id: string;
|
||||
name: string;
|
||||
size: number;
|
||||
type: string;
|
||||
createdAt: string;
|
||||
};
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { type EmailFormData } from '@/workflow/workflow-steps/workflow-actions/email-action/types/EmailFormData';
|
||||
import { type WorkflowEmailAction } from '@/workflow/workflow-steps/workflow-actions/email-action/types/WorkflowEmailAction';
|
||||
import { useState } from 'react';
|
||||
import { type EmailFormData } from '@/workflow/types/EmailFormData';
|
||||
import { type WorkflowEmailAction } from '@/workflow/types/WorkflowEmailAction';
|
||||
import { type JsonValue } from 'type-fest';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import { type WorkflowHttpRequestAction } from '@/workflow/types/Workflow';
|
||||
import { type BaseOutputSchemaV2 } from 'twenty-shared/workflow';
|
||||
import { parseAndValidateVariableFriendlyStringifiedJson } from '@/workflow/utils/parseAndValidateVariableFriendlyStringifiedJson';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useState } from 'react';
|
||||
import { type BaseOutputSchemaV2 } from 'twenty-shared/workflow';
|
||||
import { convertOutputSchemaToJson } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/convertOutputSchemaToJson';
|
||||
import { getHttpRequestOutputSchema } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/getHttpRequestOutputSchema';
|
||||
|
||||
|
||||
+1
-2
@@ -3,8 +3,7 @@ import { gql } from '@apollo/client';
|
||||
export const UPLOAD_WORKSPACE_LOGO = gql`
|
||||
mutation UploadWorkspaceLogo($file: Upload!) {
|
||||
uploadWorkspaceLogo(file: $file) {
|
||||
path
|
||||
token
|
||||
url
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPLOAD_WORKSPACE_LOGO_LEGACY = gql`
|
||||
mutation UploadWorkspaceLogoLegacy($file: Upload!) {
|
||||
uploadWorkspaceLogoLegacy(file: $file) {
|
||||
path
|
||||
token
|
||||
}
|
||||
}
|
||||
`;
|
||||
Reference in New Issue
Block a user