Improve lazy loading (#12393)
Creating manual chunk was a bad idea, we should always solve lazy loading problem at the source instance. Setting a 4.5MB for the index bundle size, CI will fail if we go above. There is still a lot of room for optimizations! - More agressive lazy loading (e.g. xyflow and tiptap are still loaded in index!) - Add a prefetch mechanism - Add stronger CI checks to make sure libraries we've set asides are not added back - Fix AllIcons component with does not work as intended (loaded on initial load)
This commit is contained in:
@ -6,7 +6,6 @@ import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { ResponsiveLine } from '@nivo/line';
|
||||
import { isNumber } from '@tiptap/core';
|
||||
import {
|
||||
QueueMetricsTimeRange,
|
||||
useGetQueueMetricsQuery,
|
||||
@ -204,11 +203,12 @@ export const WorkerMetricsGraph = ({
|
||||
.filter(([key]) => key !== '__typename')
|
||||
.map(([key, value]) => ({
|
||||
label: key.charAt(0).toUpperCase() + key.slice(1),
|
||||
value: isNumber(value)
|
||||
? value
|
||||
: Array.isArray(value)
|
||||
? value.length
|
||||
: String(value),
|
||||
value:
|
||||
typeof value === 'number'
|
||||
? value
|
||||
: Array.isArray(value)
|
||||
? value.length
|
||||
: String(value),
|
||||
}))}
|
||||
gridAutoColumns="1fr 1fr"
|
||||
labelAlign="left"
|
||||
|
||||
@ -7,7 +7,7 @@ import { countryCodeToCallingCode } from '@/settings/data-model/fields/preview/u
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { CountryCode } from 'libphonenumber-js';
|
||||
import type { CountryCode } from 'libphonenumber-js';
|
||||
import { IconCircleOff, IconComponentProps, IconMap } from 'twenty-ui/display';
|
||||
import { z } from 'zod';
|
||||
import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString';
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import dagre from '@dagrejs/dagre';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { Edge, Node } from '@xyflow/react';
|
||||
import { useEffect } from 'react';
|
||||
@ -21,81 +20,91 @@ export const SettingsDataModelOverviewEffect = ({
|
||||
useFilteredObjectMetadataItems();
|
||||
|
||||
useEffect(() => {
|
||||
const g = new dagre.graphlib.Graph();
|
||||
g.setGraph({ rankdir: 'LR' });
|
||||
g.setDefaultEdgeLabel(() => ({}));
|
||||
const loadDagreAndLayout = async () => {
|
||||
const dagre = await import('@dagrejs/dagre');
|
||||
|
||||
const edges: Edge[] = [];
|
||||
const nodes = [];
|
||||
let i = 0;
|
||||
for (const object of items) {
|
||||
nodes.push({
|
||||
id: object.namePlural,
|
||||
width: 220,
|
||||
height: 100,
|
||||
position: { x: i * 300, y: 0 },
|
||||
data: object,
|
||||
type: 'object',
|
||||
});
|
||||
g.setNode(object.namePlural, { width: 220, height: 100 });
|
||||
const g = new dagre.default.graphlib.Graph();
|
||||
g.setGraph({ rankdir: 'LR' });
|
||||
g.setDefaultEdgeLabel(() => ({}));
|
||||
|
||||
for (const field of object.fields) {
|
||||
if (
|
||||
isDefined(field.relationDefinition) &&
|
||||
isDefined(
|
||||
items.find(
|
||||
(x) => x.id === field.relationDefinition?.targetObjectMetadata.id,
|
||||
),
|
||||
)
|
||||
) {
|
||||
const sourceObj =
|
||||
field.relationDefinition?.sourceObjectMetadata.namePlural;
|
||||
const targetObj =
|
||||
field.relationDefinition?.targetObjectMetadata.namePlural;
|
||||
const edges: Edge[] = [];
|
||||
const nodes: Node[] = [];
|
||||
let i = 0;
|
||||
for (const object of items) {
|
||||
nodes.push({
|
||||
id: object.namePlural,
|
||||
width: 220,
|
||||
height: 100,
|
||||
position: { x: i * 300, y: 0 },
|
||||
data: object,
|
||||
type: 'object',
|
||||
});
|
||||
g.setNode(object.namePlural, { width: 220, height: 100 });
|
||||
|
||||
edges.push({
|
||||
id: `${sourceObj}-${targetObj}`,
|
||||
source: object.namePlural,
|
||||
sourceHandle: `${field.id}-right`,
|
||||
target: field.relationDefinition.targetObjectMetadata.namePlural,
|
||||
targetHandle: `${field.relationDefinition.targetObjectMetadata}-left`,
|
||||
type: 'smoothstep',
|
||||
style: {
|
||||
strokeWidth: 1,
|
||||
stroke: theme.color.gray,
|
||||
},
|
||||
markerEnd: 'marker',
|
||||
markerStart: 'marker',
|
||||
data: {
|
||||
sourceField: field.id,
|
||||
targetField: field.relationDefinition.targetFieldMetadata.id,
|
||||
relation: field.relationDefinition.direction,
|
||||
sourceObject: sourceObj,
|
||||
targetObject: targetObj,
|
||||
},
|
||||
});
|
||||
if (!isUndefinedOrNull(sourceObj) && !isUndefinedOrNull(targetObj)) {
|
||||
g.setEdge(sourceObj, targetObj);
|
||||
for (const field of object.fields) {
|
||||
if (
|
||||
isDefined(field.relationDefinition) &&
|
||||
isDefined(
|
||||
items.find(
|
||||
(x) =>
|
||||
x.id === field.relationDefinition?.targetObjectMetadata.id,
|
||||
),
|
||||
)
|
||||
) {
|
||||
const sourceObj =
|
||||
field.relationDefinition?.sourceObjectMetadata.namePlural;
|
||||
const targetObj =
|
||||
field.relationDefinition?.targetObjectMetadata.namePlural;
|
||||
|
||||
edges.push({
|
||||
id: `${sourceObj}-${targetObj}`,
|
||||
source: object.namePlural,
|
||||
sourceHandle: `${field.id}-right`,
|
||||
target: field.relationDefinition.targetObjectMetadata.namePlural,
|
||||
targetHandle: `${field.relationDefinition.targetObjectMetadata}-left`,
|
||||
type: 'smoothstep',
|
||||
style: {
|
||||
strokeWidth: 1,
|
||||
stroke: theme.color.gray,
|
||||
},
|
||||
markerEnd: 'marker',
|
||||
markerStart: 'marker',
|
||||
data: {
|
||||
sourceField: field.id,
|
||||
targetField: field.relationDefinition.targetFieldMetadata.id,
|
||||
relation: field.relationDefinition.direction,
|
||||
sourceObject: sourceObj,
|
||||
targetObject: targetObj,
|
||||
},
|
||||
});
|
||||
if (
|
||||
!isUndefinedOrNull(sourceObj) &&
|
||||
!isUndefinedOrNull(targetObj)
|
||||
) {
|
||||
g.setEdge(sourceObj, targetObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
dagre.layout(g);
|
||||
dagre.default.layout(g);
|
||||
|
||||
nodes.forEach((node) => {
|
||||
const nodeWithPosition = g.node(node.id);
|
||||
node.position = {
|
||||
// We are shifting the dagre node position (anchor=center center) to the top left
|
||||
// so it matches the React Flow node anchor point (top left).
|
||||
x: nodeWithPosition.x - node.width / 2,
|
||||
y: nodeWithPosition.y - node.height / 2,
|
||||
};
|
||||
});
|
||||
nodes.forEach((node) => {
|
||||
const nodeWithPosition = g.node(node.id);
|
||||
node.position = {
|
||||
// We are shifting the dagre node position (anchor=center center) to the top left
|
||||
// so it matches the React Flow node anchor point (top left).
|
||||
x: nodeWithPosition.x - (node.width ?? 0) / 2,
|
||||
y: nodeWithPosition.y - (node.height ?? 0) / 2,
|
||||
};
|
||||
});
|
||||
|
||||
setNodes(nodes);
|
||||
setEdges(edges);
|
||||
setNodes(nodes);
|
||||
setEdges(edges);
|
||||
};
|
||||
|
||||
loadDagreAndLayout();
|
||||
}, [items, setEdges, setNodes, theme]);
|
||||
|
||||
return <></>;
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { INDEX_FILE_PATH } from '@/serverless-functions/constants/IndexFilePath';
|
||||
import { getFunctionInputFromSourceCode } from '@/serverless-functions/utils/getFunctionInputFromSourceCode';
|
||||
import { useGetOneServerlessFunction } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunction';
|
||||
import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode';
|
||||
import { Dispatch, SetStateAction, useState } from 'react';
|
||||
import { FindOneServerlessFunctionSourceCodeQuery } from '~/generated-metadata/graphql';
|
||||
import { serverlessFunctionTestDataFamilyState } from '@/workflow/states/serverlessFunctionTestDataFamilyState';
|
||||
import { Dispatch, SetStateAction, useState } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { getFunctionInputFromSourceCode } from '@/serverless-functions/utils/getFunctionInputFromSourceCode';
|
||||
import { INDEX_FILE_PATH } from '@/serverless-functions/constants/IndexFilePath';
|
||||
import { FindOneServerlessFunctionSourceCodeQuery } from '~/generated-metadata/graphql';
|
||||
|
||||
export type ServerlessFunctionNewFormValues = {
|
||||
name: string;
|
||||
|
||||
Reference in New Issue
Block a user