mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-22 03:17:40 +03:00
Merge branch 'main' into fix-settings-relations-issues
This commit is contained in:
commit
922d9efe54
@ -90,8 +90,6 @@ services:
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
|
12
packages/twenty-docker/scripts/1-click.sh
Normal file
12
packages/twenty-docker/scripts/1-click.sh
Normal file
@ -0,0 +1,12 @@
|
||||
pull_version=${VERSION:-$(curl -s https://api.github.com/repos/twentyhq/twenty/releases/latest | grep '"tag_name":' | cut -d '"' -f 4)}
|
||||
pull_branch=${BRANCH:-$pull_version}
|
||||
|
||||
version_num=${pull_version#v}
|
||||
target_version="0.32.4"
|
||||
|
||||
# We moved the install script to a different location in v0.32.4
|
||||
if [[ -n "$BRANCH" ]] || [[ "$(printf '%s\n' "$target_version" "$version_num" | sort -V | head -n1)" != "$version_num" ]]; then
|
||||
curl -sL "https://raw.githubusercontent.com/twentyhq/twenty/$pull_branch/packages/twenty-docker/scripts/install.sh" | bash -s -- "$VERSION" "$BRANCH"
|
||||
else
|
||||
curl -sL "https://raw.githubusercontent.com/twentyhq/twenty/$pull_branch/install.sh" | bash -s -- "$VERSION" "$BRANCH"
|
||||
fi
|
@ -19,6 +19,7 @@ import {
|
||||
import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map';
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
|
||||
export class GraphqlQueryParser {
|
||||
private fieldMetadataMapByName: FieldMetadataMap;
|
||||
@ -108,9 +109,10 @@ export class GraphqlQueryParser {
|
||||
parentObjectMetadata: ObjectMetadataItemWithFieldMaps,
|
||||
graphqlSelectedFields: Partial<Record<string, any>>,
|
||||
): GraphqlQuerySelectedFieldsResult {
|
||||
const parentFields =
|
||||
this.objectMetadataMaps.byNameSingular[parentObjectMetadata.nameSingular]
|
||||
?.fieldsByName;
|
||||
const parentFields = getObjectMetadataMapItemByNameSingular(
|
||||
this.objectMetadataMaps,
|
||||
parentObjectMetadata.nameSingular,
|
||||
)?.fieldsByName;
|
||||
|
||||
if (!parentFields) {
|
||||
throw new Error(
|
||||
|
@ -17,6 +17,7 @@ import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-meta
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
import { CompositeFieldMetadataType } from 'src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory';
|
||||
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
|
||||
import { isPlainObject } from 'src/utils/is-plain-object';
|
||||
@ -143,7 +144,10 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
||||
);
|
||||
}
|
||||
|
||||
const objectMetadata = this.objectMetadataMaps.byNameSingular[objectName];
|
||||
const objectMetadata = getObjectMetadataMapItemByNameSingular(
|
||||
this.objectMetadataMaps,
|
||||
objectName,
|
||||
);
|
||||
|
||||
if (!objectMetadata) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
|
@ -7,6 +7,10 @@ import {
|
||||
|
||||
import { ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper';
|
||||
import {
|
||||
getRelationMetadata,
|
||||
@ -15,6 +19,7 @@ import {
|
||||
import { AggregationField } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-available-aggregations-from-object-fields.util';
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||
import { deduceRelationDirection } from 'src/engine/utils/deduce-relation-direction.util';
|
||||
|
||||
@ -177,13 +182,23 @@ export class ProcessNestedRelationsHelper {
|
||||
joinField: `${inverseRelationName}Id`,
|
||||
});
|
||||
|
||||
const referenceObjectMetadataItemWithFieldsMaps =
|
||||
getObjectMetadataMapItemByNameSingular(
|
||||
objectMetadataMaps,
|
||||
referenceObjectMetadata.nameSingular,
|
||||
);
|
||||
|
||||
if (!referenceObjectMetadataItemWithFieldsMaps) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Object ${referenceObjectMetadata.nameSingular} not found`,
|
||||
GraphqlQueryRunnerExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
if (Object.keys(nestedRelations).length > 0) {
|
||||
await this.processNestedRelations({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem:
|
||||
objectMetadataMaps.byNameSingular[
|
||||
referenceObjectMetadata.nameSingular
|
||||
],
|
||||
parentObjectMetadataItem: referenceObjectMetadataItemWithFieldsMaps,
|
||||
parentObjectRecords: relationResults as ObjectRecord[],
|
||||
parentObjectRecordsAggregatedValues: relationAggregatedFieldsResult,
|
||||
relations: nestedRelations as Record<
|
||||
@ -258,13 +273,23 @@ export class ProcessNestedRelationsHelper {
|
||||
relationName,
|
||||
});
|
||||
|
||||
const referenceObjectMetadataItemWithFieldsMaps =
|
||||
getObjectMetadataMapItemByNameSingular(
|
||||
objectMetadataMaps,
|
||||
referenceObjectMetadata.nameSingular,
|
||||
);
|
||||
|
||||
if (!referenceObjectMetadataItemWithFieldsMaps) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Object ${referenceObjectMetadata.nameSingular} not found`,
|
||||
GraphqlQueryRunnerExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
if (Object.keys(nestedRelations).length > 0) {
|
||||
await this.processNestedRelations({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem:
|
||||
objectMetadataMaps.byNameSingular[
|
||||
referenceObjectMetadata.nameSingular
|
||||
],
|
||||
parentObjectMetadataItem: referenceObjectMetadataItemWithFieldsMaps,
|
||||
parentObjectRecords: relationResults as ObjectRecord[],
|
||||
parentObjectRecordsAggregatedValues: relationAggregatedFieldsResult,
|
||||
relations: nestedRelations as Record<
|
||||
|
@ -22,6 +22,7 @@ import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/g
|
||||
import { settings } from 'src/engine/constants/settings';
|
||||
import { DUPLICATE_CRITERIA_COLLECTION } from 'src/engine/core-modules/duplicate/constants/duplicate-criteria.constants';
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
|
||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||
@ -56,10 +57,21 @@ export class GraphqlQueryFindDuplicatesResolverService
|
||||
objectMetadataItemWithFieldMaps.nameSingular,
|
||||
);
|
||||
|
||||
const objectMetadataItemWithFieldsMaps =
|
||||
getObjectMetadataMapItemByNameSingular(
|
||||
objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps.nameSingular,
|
||||
);
|
||||
|
||||
if (!objectMetadataItemWithFieldsMaps) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Object ${objectMetadataItemWithFieldMaps.nameSingular} not found`,
|
||||
GraphqlQueryRunnerExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const graphqlQueryParser = new GraphqlQueryParser(
|
||||
objectMetadataMaps.byNameSingular[
|
||||
objectMetadataItemWithFieldMaps.nameSingular
|
||||
].fieldsByName,
|
||||
objectMetadataItemWithFieldsMaps?.fieldsByName,
|
||||
objectMetadataMaps,
|
||||
);
|
||||
|
||||
|
@ -2,6 +2,5 @@ import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/typ
|
||||
|
||||
export type ObjectMetadataMaps = {
|
||||
byId: Record<string, ObjectMetadataItemWithFieldMaps>;
|
||||
byNameSingular: Record<string, ObjectMetadataItemWithFieldMaps>;
|
||||
byNamePlural: Record<string, ObjectMetadataItemWithFieldMaps>;
|
||||
idByNameSingular: Record<string, string>;
|
||||
};
|
||||
|
@ -0,0 +1,42 @@
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
|
||||
describe('getObjectMetadataMapItemByNameSingular', () => {
|
||||
it('should return the correct metadata item when given a valid singular name', () => {
|
||||
const mockMetadataItem = {
|
||||
id: 'test-id',
|
||||
nameSingular: 'company',
|
||||
} as ObjectMetadataItemWithFieldMaps;
|
||||
|
||||
const mockObjectMetadataMaps: ObjectMetadataMaps = {
|
||||
byId: {
|
||||
'test-id': mockMetadataItem,
|
||||
},
|
||||
idByNameSingular: {
|
||||
company: 'test-id',
|
||||
},
|
||||
};
|
||||
|
||||
const result = getObjectMetadataMapItemByNameSingular(
|
||||
mockObjectMetadataMaps,
|
||||
'company',
|
||||
);
|
||||
|
||||
expect(result).toBe(mockMetadataItem);
|
||||
});
|
||||
|
||||
it('should return undefined when the singular name does not exist', () => {
|
||||
const mockObjectMetadataMaps: ObjectMetadataMaps = {
|
||||
byId: {},
|
||||
idByNameSingular: {},
|
||||
};
|
||||
|
||||
const result = getObjectMetadataMapItemByNameSingular(
|
||||
mockObjectMetadataMaps,
|
||||
'nonexistent',
|
||||
);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
@ -9,8 +9,7 @@ export const generateObjectMetadataMaps = (
|
||||
): ObjectMetadataMaps => {
|
||||
const objectMetadataMaps: ObjectMetadataMaps = {
|
||||
byId: {},
|
||||
byNameSingular: {},
|
||||
byNamePlural: {},
|
||||
idByNameSingular: {},
|
||||
};
|
||||
|
||||
for (const objectMetadata of objectMetadataCollection) {
|
||||
@ -29,10 +28,8 @@ export const generateObjectMetadataMaps = (
|
||||
};
|
||||
|
||||
objectMetadataMaps.byId[objectMetadata.id] = processedObjectMetadata;
|
||||
objectMetadataMaps.byNameSingular[objectMetadata.nameSingular] =
|
||||
processedObjectMetadata;
|
||||
objectMetadataMaps.byNamePlural[objectMetadata.namePlural] =
|
||||
processedObjectMetadata;
|
||||
objectMetadataMaps.idByNameSingular[objectMetadata.nameSingular] =
|
||||
objectMetadata.id;
|
||||
}
|
||||
|
||||
return objectMetadataMaps;
|
||||
|
@ -0,0 +1,11 @@
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
|
||||
export const getObjectMetadataMapItemByNameSingular = (
|
||||
objectMetadataMaps: ObjectMetadataMaps,
|
||||
nameSingular: string,
|
||||
): ObjectMetadataItemWithFieldMaps | undefined => {
|
||||
return objectMetadataMaps.byId[
|
||||
objectMetadataMaps.idByNameSingular[nameSingular]
|
||||
];
|
||||
};
|
@ -23,6 +23,7 @@ import { UpsertOptions } from 'typeorm/repository/UpsertOptions';
|
||||
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
||||
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
import { WorkspaceEntitiesStorage } from 'src/engine/twenty-orm/storage/workspace-entities.storage';
|
||||
import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
|
||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||
@ -630,16 +631,20 @@ export class WorkspaceRepository<
|
||||
throw new Error('Object metadata name is missing');
|
||||
}
|
||||
|
||||
const objectMetadata =
|
||||
this.internalContext.objectMetadataMaps.byNameSingular[
|
||||
objectMetadataName
|
||||
];
|
||||
const objectMetadata = getObjectMetadataMapItemByNameSingular(
|
||||
this.internalContext.objectMetadataMaps,
|
||||
objectMetadataName,
|
||||
);
|
||||
|
||||
if (!objectMetadata) {
|
||||
throw new Error(
|
||||
`Object metadata for object "${objectMetadataName}" is missing ` +
|
||||
`in workspace "${this.internalContext.workspaceId}" ` +
|
||||
`with object metadata collection length: ${this.internalContext.objectMetadataMaps.byNameSingular.length}`,
|
||||
`with object metadata collection length: ${
|
||||
Object.keys(
|
||||
this.internalContext.objectMetadataMaps.idByNameSingular,
|
||||
).length
|
||||
}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/c
|
||||
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||
@ -179,7 +180,10 @@ export class RecordCRUDWorkflowAction implements WorkflowAction {
|
||||
}
|
||||
|
||||
const objectMetadataItemWithFieldsMaps =
|
||||
objectMetadataMaps.byNameSingular[workflowActionInput.objectName];
|
||||
getObjectMetadataMapItemByNameSingular(
|
||||
objectMetadataMaps,
|
||||
workflowActionInput.objectName,
|
||||
);
|
||||
|
||||
if (!objectMetadataItemWithFieldsMaps) {
|
||||
throw new RecordCRUDActionException(
|
||||
|
@ -31,7 +31,7 @@ bash <(curl -sL https://git.new/20)
|
||||
|
||||
To install a specific version or branch:
|
||||
```bash
|
||||
VERSION=x.y.z BRANCH=branch-name bash <(curl -sL https://git.new/20)
|
||||
VERSION=vx.y.z BRANCH=branch-name bash <(curl -sL https://git.new/20)
|
||||
```
|
||||
- Replace x.y.z with the desired version number.
|
||||
- Replace branch-name with the name of the branch you want to install.
|
||||
|
Loading…
Reference in New Issue
Block a user