From 6fef12596536d1a0857f153433ad133d9fc44b92 Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:50:04 +0200 Subject: [PATCH 01/38] Use search instead of findMany in relation pickers (#7798) First step of #https://github.com/twentyhq/twenty/issues/3298. Here we update the search endpoint to allow for a filter argument, which we currently use in the relation pickers to restrict or exclude ids from search. In a future PR we will try to simplify the search logic in the FE --- .../effect-components/GotoHotkeysEffect.tsx | 1 + ...ionDrawerSectionForObjectMetadataItems.tsx | 1 + ...bjectMetadataItemsRelationPickerEffect.tsx | 29 -------- .../object-record/hooks/useSearchRecords.ts | 10 ++- .../components/RelationFromManyFieldInput.tsx | 2 - .../RecordDetailRelationSection.tsx | 2 - .../SingleEntitySelectMenuItemsWithSearch.tsx | 4 -- .../hooks/useRelationPickerEntitiesOptions.ts | 17 ++--- .../utils/generateSearchRecordsQuery.ts | 8 ++- .../useFilteredSearchEntityQuery.test.tsx | 4 +- .../hooks/useFilteredSearchEntityQuery.ts | 69 +++---------------- .../twenty-front/src/testing/graphqlMocks.ts | 46 +++++++++++++ .../graphql-query-search-resolver.service.ts | 46 ++++++++++--- .../workspace-resolvers-builder.interface.ts | 5 +- .../utils/get-resolver-args.util.ts | 4 ++ 15 files changed, 123 insertions(+), 125 deletions(-) delete mode 100644 packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsRelationPickerEffect.tsx diff --git a/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffect.tsx b/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffect.tsx index 15d371f9f44a..202b58b963e5 100644 --- a/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffect.tsx +++ b/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffect.tsx @@ -11,6 +11,7 @@ export const GotoHotkeys = () => { return nonSystemActiveObjectMetadataItems.map((objectMetadataItem) => ( diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx index 9960670d1beb..f90a160b57c4 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx @@ -85,6 +85,7 @@ export const NavigationDrawerSectionForObjectMetadataItems = ({ objectMetadataItemsForNavigationItems.map( (objectMetadataItem) => ( ), diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsRelationPickerEffect.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsRelationPickerEffect.tsx deleted file mode 100644 index 1d2d1ecd74b9..000000000000 --- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsRelationPickerEffect.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useEffect } from 'react'; - -import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker'; - -export const ObjectMetadataItemsRelationPickerEffect = ({ - relationPickerScopeId, -}: { - relationPickerScopeId?: string; -} = {}) => { - const { setSearchQuery } = useRelationPicker({ relationPickerScopeId }); - - const computeFilterFields = (relationPickerType: string) => { - if (relationPickerType === 'company') { - return ['name']; - } - - if (['workspaceMember', 'person'].includes(relationPickerType)) { - return ['name.firstName', 'name.lastName']; - } - - return ['name']; - }; - - useEffect(() => { - setSearchQuery({ computeFilterFields }); - }, [setSearchQuery]); - - return <>; -}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useSearchRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useSearchRecords.ts index 175f84554f19..7c1f90162597 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useSearchRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useSearchRecords.ts @@ -13,10 +13,11 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useQuery, WatchQueryFetchPolicy } from '@apollo/client'; import { useMemo } from 'react'; import { useRecoilValue } from 'recoil'; +import { isDefined } from '~/utils/isDefined'; import { logError } from '~/utils/logError'; export type UseSearchRecordsParams = ObjectMetadataItemIdentifier & - RecordGqlOperationVariables & { + Pick & { onError?: (error?: Error) => void; skip?: boolean; recordGqlFields?: RecordGqlOperationGqlRecordFields; @@ -29,6 +30,7 @@ export const useSearchRecords = ({ searchInput, limit, skip, + filter, recordGqlFields, fetchPolicy, }: UseSearchRecordsParams) => { @@ -45,10 +47,14 @@ export const useSearchRecords = ({ const { data, loading, error, previousData } = useQuery(searchRecordsQuery, { skip: - skip || !objectMetadataItem || !currentWorkspaceMember || !searchInput, + skip || + !objectMetadataItem || + !currentWorkspaceMember || + !isDefined(searchInput), variables: { search: searchInput, limit: limit, + filter: filter, }, fetchPolicy: fetchPolicy, onError: (error) => { diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput.tsx index be1cba38161b..f0cbf686dfc2 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput.tsx @@ -1,6 +1,5 @@ import { useContext } from 'react'; -import { ObjectMetadataItemsRelationPickerEffect } from '@/object-metadata/components/ObjectMetadataItemsRelationPickerEffect'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { RelationFromManyFieldInputMultiRecordsEffect } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect'; @@ -54,7 +53,6 @@ export const RelationFromManyFieldInput = ({ return ( <> - ) : ( <> - - gql` - query Search${capitalize(objectMetadataItem.namePlural)}($search: String, $limit: Int) { - ${getSearchRecordsQueryResponseField(objectMetadataItem.namePlural)}(searchInput: $search, limit: $limit){ + query Search${capitalize(objectMetadataItem.namePlural)}($search: String, $limit: Int, $filter: ${capitalize( + objectMetadataItem.nameSingular, + )}FilterInput) { + ${getSearchRecordsQueryResponseField(objectMetadataItem.namePlural)}(searchInput: $search, limit: $limit, filter: $filter){ edges { node ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, diff --git a/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx b/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx index 263b70decf0f..6b2409af45a3 100644 --- a/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx +++ b/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx @@ -80,13 +80,11 @@ describe('useFilteredSearchEntityQuery', () => { setMetadataItems(generatedMockObjectMetadataItems); return useFilteredSearchEntityQuery({ - orderByField: 'name', - filters: [{ fieldNames: ['name'], filter: 'Entity' }], - sortOrder: 'AscNullsLast', selectedIds: ['1'], limit: 10, excludeRecordIds: ['2'], objectNameSingular: 'person', + searchFilter: 'Entity', }); }, { wrapper: Wrapper }, diff --git a/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts b/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts index 06ba43f92e60..9d6973385230 100644 --- a/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts +++ b/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts @@ -1,39 +1,26 @@ -import { isNonEmptyString } from '@sniptt/guards'; - import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier'; import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit'; -import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; -import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { useSearchRecords } from '@/object-record/hooks/useSearchRecords'; import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect'; import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables'; -import { makeOrFilterVariables } from '@/object-record/utils/makeOrFilterVariables'; -import { OrderBy } from '@/types/OrderBy'; -import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; import { isDefined } from '~/utils/isDefined'; -type SearchFilter = { fieldNames: string[]; filter: string | number }; - // TODO: use this for all search queries, because we need selectedEntities and entitiesToSelect each time we want to search // Filtered entities to select are export const useFilteredSearchEntityQuery = ({ - orderByField, - filters, - sortOrder = 'AscNullsLast', selectedIds, limit, excludeRecordIds = [], objectNameSingular, + searchFilter, }: { - orderByField: string; - filters: SearchFilter[]; - sortOrder?: OrderBy; selectedIds: string[]; limit?: number; excludeRecordIds?: string[]; objectNameSingular: string; + searchFilter?: string; }): EntitiesForMultipleEntitySelect => { const { mapToObjectRecordIdentifier } = useMapToObjectRecordIdentifier({ objectNameSingular, @@ -46,55 +33,21 @@ export const useFilteredSearchEntityQuery = ({ const selectedIdsFilter = { id: { in: selectedIds } }; const { loading: selectedRecordsLoading, records: selectedRecords } = - useFindManyRecords({ + useSearchRecords({ objectNameSingular, filter: selectedIdsFilter, - orderBy: [{ [orderByField]: sortOrder }], skip: !selectedIds.length, + searchInput: searchFilter, }); - const searchFilters = filters.map(({ fieldNames, filter }) => { - if (!isNonEmptyString(filter)) { - return undefined; - } - - const formattedFilters = fieldNames.reduce( - (previousValue: RecordGqlOperationFilter[], fieldName) => { - const [parentFieldName, subFieldName] = fieldName.split('.'); - - if (isNonEmptyString(subFieldName)) { - // Composite field - return [ - ...previousValue, - ...generateILikeFiltersForCompositeFields(filter, parentFieldName, [ - subFieldName, - ]), - ]; - } - - return [ - ...previousValue, - { - [fieldName]: { - ilike: `%${filter}%`, - }, - }, - ]; - }, - [], - ); - - return makeOrFilterVariables(formattedFilters); - }); - const { loading: filteredSelectedRecordsLoading, records: filteredSelectedRecords, - } = useFindManyRecords({ + } = useSearchRecords({ objectNameSingular, - filter: makeAndFilterVariables([...searchFilters, selectedIdsFilter]), - orderBy: [{ [orderByField]: sortOrder }], + filter: selectedIdsFilter, skip: !selectedIds.length, + searchInput: searchFilter, }); const notFilterIds = [...selectedIds, ...excludeRecordIds]; @@ -102,11 +55,11 @@ export const useFilteredSearchEntityQuery = ({ ? { not: { id: { in: notFilterIds } } } : undefined; const { loading: recordsToSelectLoading, records: recordsToSelect } = - useFindManyRecords({ + useSearchRecords({ objectNameSingular, - filter: makeAndFilterVariables([...searchFilters, notFilter]), + filter: notFilter, limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT, - orderBy: [{ [orderByField]: sortOrder }], + searchInput: searchFilter, }); return { diff --git a/packages/twenty-front/src/testing/graphqlMocks.ts b/packages/twenty-front/src/testing/graphqlMocks.ts index 1cb7c4b3aef5..d634890a5f9b 100644 --- a/packages/twenty-front/src/testing/graphqlMocks.ts +++ b/packages/twenty-front/src/testing/graphqlMocks.ts @@ -113,6 +113,52 @@ export const graphqlMocks = { }, }); }), + graphql.query('SearchWorkspaceMembers', () => { + return HttpResponse.json({ + data: { + searchWorkspaceMembers: { + edges: mockWorkspaceMembers.map((member) => ({ + node: { + ...member, + messageParticipants: { + edges: [], + __typename: 'MessageParticipantConnection', + }, + authoredAttachments: { + edges: [], + __typename: 'AttachmentConnection', + }, + authoredComments: { + edges: [], + __typename: 'CommentConnection', + }, + accountOwnerForCompanies: { + edges: [], + __typename: 'CompanyConnection', + }, + authoredActivities: { + edges: [], + __typename: 'ActivityConnection', + }, + favorites: { + edges: [], + __typename: 'FavoriteConnection', + }, + connectedAccounts: { + edges: [], + __typename: 'ConnectedAccountConnection', + }, + assignedActivities: { + edges: [], + __typename: 'ActivityConnection', + }, + }, + cursor: null, + })), + }, + }, + }); + }), graphql.query('FindManyViewFields', ({ variables }) => { const viewId = variables.filter.view.eq; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service.ts index cfd570281187..378dfff97fc4 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service.ts @@ -4,16 +4,19 @@ import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/int import { Record as IRecord, OrderByDirection, + RecordFilter, } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; import { IConnection } from 'src/engine/api/graphql/workspace-query-runner/interfaces/connection.interface'; import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface'; import { SearchResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant'; +import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/constants/search-vector-field.constants'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; +import { isDefined } from 'src/utils/is-defined'; @Injectable() export class GraphqlQuerySearchResolverService @@ -24,11 +27,19 @@ export class GraphqlQuerySearchResolverService private readonly featureFlagService: FeatureFlagService, ) {} - async resolve( + async resolve< + ObjectRecord extends IRecord = IRecord, + Filter extends RecordFilter = RecordFilter, + >( args: SearchResolverArgs, options: WorkspaceQueryRunnerOptions, ): Promise> { - const { authContext, objectMetadataItem, objectMetadataMap } = options; + const { + authContext, + objectMetadataItem, + objectMetadataMapItem, + objectMetadataMap, + } = options; const repository = await this.twentyORMGlobalManager.getRepositoryForWorkspace( @@ -39,7 +50,7 @@ export class GraphqlQuerySearchResolverService const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMap); - if (!args.searchInput) { + if (!isDefined(args.searchInput)) { return typeORMObjectRecordsParser.createConnection({ objectRecords: [], objectName: objectMetadataItem.nameSingular, @@ -54,11 +65,27 @@ export class GraphqlQuerySearchResolverService const limit = args?.limit ?? QUERY_MAX_RECORDS; - const resultsWithTsVector = (await repository - .createQueryBuilder() - .where(`"${SEARCH_VECTOR_FIELD.name}" @@ to_tsquery(:searchTerms)`, { - searchTerms, - }) + const queryBuilder = repository.createQueryBuilder( + objectMetadataItem.nameSingular, + ); + const graphqlQueryParser = new GraphqlQueryParser( + objectMetadataMapItem.fields, + objectMetadataMap, + ); + + const queryBuilderWithFilter = graphqlQueryParser.applyFilterToBuilder( + queryBuilder, + objectMetadataMapItem.nameSingular, + args.filter ?? ({} as Filter), + ); + + const resultsWithTsVector = (await queryBuilderWithFilter + .andWhere( + searchTerms === '' + ? `"${SEARCH_VECTOR_FIELD.name}" IS NOT NULL` + : `"${SEARCH_VECTOR_FIELD.name}" @@ to_tsquery(:searchTerms)`, + searchTerms === '' ? {} : { searchTerms }, + ) .orderBy( `ts_rank("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTerms))`, 'DESC', @@ -84,6 +111,9 @@ export class GraphqlQuerySearchResolverService } private formatSearchTerms(searchTerm: string) { + if (searchTerm === '') { + return ''; + } const words = searchTerm.trim().split(/\s+/); const formattedWords = words.map((word) => { const escapedWord = word.replace(/[\\:'&|!()]/g, '\\$&'); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface.ts index 219b185c451e..69bc97777b10 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface.ts @@ -48,8 +48,11 @@ export interface FindDuplicatesResolverArgs< data?: Data[]; } -export interface SearchResolverArgs { +export interface SearchResolverArgs< + Filter extends RecordFilter = RecordFilter, +> { searchInput?: string; + filter?: Filter; limit?: number; } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/get-resolver-args.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/get-resolver-args.util.ts index 7e1755218730..b50047e62e2a 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/get-resolver-args.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/get-resolver-args.util.ts @@ -147,6 +147,10 @@ export const getResolverArgs = ( type: GraphQLInt, isNullable: true, }, + filter: { + kind: InputTypeDefinitionKind.Filter, + isNullable: true, + }, }; default: throw new Error(`Unknown resolver type: ${type}`); From 5a23d1eea8b61d026d2c7dbcfc87489a28d9f00a Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:14:08 +0200 Subject: [PATCH 02/38] [sentry fix] handle undefined createdBy case (#7818) Fix sentry https://twenty-v7.sentry.io/issues/5998085857/?alert_rule_id=15135094&alert_type=issue&environment=prod¬ification_uuid=9a6c6c3d-6bd1-4c7f-bf27-8acb3571bbc3&project=4507072499810304&referrer=discord --- .../core-modules/actor/query-hooks/created-by.pre-query-hook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/twenty-server/src/engine/core-modules/actor/query-hooks/created-by.pre-query-hook.ts b/packages/twenty-server/src/engine/core-modules/actor/query-hooks/created-by.pre-query-hook.ts index 2a90843f1d69..0ef8bab573b7 100644 --- a/packages/twenty-server/src/engine/core-modules/actor/query-hooks/created-by.pre-query-hook.ts +++ b/packages/twenty-server/src/engine/core-modules/actor/query-hooks/created-by.pre-query-hook.ts @@ -101,7 +101,7 @@ export class CreatedByPreQueryHook implements WorkspaceQueryHookInstance { for (const datum of payload.data) { // Front-end can fill the source field - if (createdBy && (!datum.createdBy || !datum.createdBy.name)) { + if (createdBy && (!datum.createdBy || !datum.createdBy?.name)) { datum.createdBy = { ...createdBy, source: datum.createdBy?.source ?? createdBy.source, From 9c8eeeea9d01f28909fc13cadbaa7c4e92706462 Mon Sep 17 00:00:00 2001 From: martmull Date: Fri, 18 Oct 2024 16:13:12 +0200 Subject: [PATCH 03/38] Start twenty-server:worker when npx nx start (#7820) - start the worker service when launching `npx nx start` - update documentation --- package.json | 2 +- .../twenty-website/src/content/developers/local-setup.mdx | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index a4dc90df92ac..f86d4c1b9d08 100644 --- a/package.json +++ b/package.json @@ -347,7 +347,7 @@ "version": "0.2.1", "nx": {}, "scripts": { - "start": "npx nx run-many -t start -p twenty-server twenty-front" + "start": "npx nx run-many -t start worker -p twenty-server twenty-front" }, "workspaces": { "packages": [ diff --git a/packages/twenty-website/src/content/developers/local-setup.mdx b/packages/twenty-website/src/content/developers/local-setup.mdx index 283aba5a9614..b66ea2ee45aa 100644 --- a/packages/twenty-website/src/content/developers/local-setup.mdx +++ b/packages/twenty-website/src/content/developers/local-setup.mdx @@ -225,13 +225,14 @@ Setup your database with the following command: npx nx database:reset twenty-server ``` -Start the server and the frontend: +Start the server, the worker and the frontend services: ```bash npx nx start twenty-server +npx nx worker twenty-server npx nx start twenty-front ``` -Alternatively, you can start both applications at once: +Alternatively, you can start all services at once: ```bash npx nx start ``` From e50117e3b096bf252304da454f7199aedca7c35f Mon Sep 17 00:00:00 2001 From: NitinPSingh <71833171+NitinPSingh@users.noreply.github.com> Date: Fri, 18 Oct 2024 21:32:43 +0530 Subject: [PATCH 04/38] fix #7781 made kanban board title and checkbox 24px (#7815) # issue: #7781 - [x] titlechip to 24px - [x] checkbox to 24px ![Screenshot 2024-10-18 134759](https://github.com/user-attachments/assets/e9d347e3-41b8-4b0d-a072-d139ed982971) ![Screenshot 2024-10-18 134708](https://github.com/user-attachments/assets/8b83f6dd-96ac-4a4e-b6ae-85d3e2923fb9) --- .../src/modules/ui/input/components/Checkbox.tsx | 10 ++++++---- .../twenty-ui/src/display/chip/components/Chip.tsx | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx b/packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx index fd3327c63f23..e19d3cb70976 100644 --- a/packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx @@ -52,7 +52,10 @@ const StyledInputContainer = styled.div` cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; display: flex; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${({ theme, checkboxSize }) => + checkboxSize === CheckboxSize.Large + ? theme.spacing(1.5) + : theme.spacing(1.25)}; position: relative; ${({ hoverable, isChecked, theme, indeterminate, disabled }) => { if (!hoverable || disabled === true) return ''; @@ -126,10 +129,9 @@ const StyledInput = styled.input` } & + label > svg { - --padding: ${({ checkboxSize }) => - checkboxSize === CheckboxSize.Large ? '2px' : '1px'}; + --padding: 0px; --size: ${({ checkboxSize }) => - checkboxSize === CheckboxSize.Large ? '16px' : '12px'}; + checkboxSize === CheckboxSize.Large ? '20px' : '14px'}; height: var(--size); left: var(--padding); position: absolute; diff --git a/packages/twenty-ui/src/display/chip/components/Chip.tsx b/packages/twenty-ui/src/display/chip/components/Chip.tsx index 48795fd42551..3bf0cd9bb90d 100644 --- a/packages/twenty-ui/src/display/chip/components/Chip.tsx +++ b/packages/twenty-ui/src/display/chip/components/Chip.tsx @@ -66,7 +66,7 @@ const StyledContainer = withTheme(styled.div< display: inline-flex; justify-content: center; gap: ${({ theme }) => theme.spacing(1)}; - height: ${({ theme }) => theme.spacing(3)}; + height: ${({ theme }) => theme.spacing(4)}; max-width: ${({ maxWidth }) => maxWidth ? `calc(${maxWidth}px - 2 * var(--chip-horizontal-padding))` From 17b934e22b66562952ad7c2d53286d89eccc2d51 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Fri, 18 Oct 2024 18:36:01 +0200 Subject: [PATCH 05/38] Migrate to shipfox --- .github/workflows/ci-front.yaml | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index 595081c0a973..506a6dce0e5e 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -43,32 +43,6 @@ jobs: - name: Front / Build storybook run: npx nx storybook:build twenty-front front-sb-test: - runs-on: ci-8-cores - timeout-minutes: 60 - needs: front-sb-build - strategy: - matrix: - storybook_scope: [pages, modules] - env: - REACT_APP_SERVER_BASE_URL: http://localhost:3000 - NX_REJECT_UNKNOWN_LOCAL_CACHE: 0 - steps: - - name: Fetch local actions - uses: actions/checkout@v4 - - name: Install dependencies - uses: ./.github/workflows/actions/yarn-install - - name: Install Playwright - run: cd packages/twenty-front && npx playwright install - - name: Front / Restore Storybook Task Cache - uses: ./.github/workflows/actions/task-cache - with: - tag: scope:frontend - tasks: storybook:build - - name: Front / Write .env - run: npx nx reset:env twenty-front - - name: Run storybook tests - run: npx nx storybook:serve-and-test:static twenty-front --configuration=${{ matrix.storybook_scope }} - front-sb-test-shipfox: runs-on: shipfox-8vcpu-ubuntu-2204 timeout-minutes: 60 needs: front-sb-build @@ -95,7 +69,7 @@ jobs: - name: Run storybook tests run: npx nx storybook:serve-and-test:static twenty-front --configuration=${{ matrix.storybook_scope }} front-sb-test-performance: - runs-on: ci-8-cores + runs-on: shipfox-8vcpu-ubuntu-2204 timeout-minutes: 60 env: REACT_APP_SERVER_BASE_URL: http://localhost:3000 From d4457d756cf847cd3615bd0f33fb708b481f6d6c Mon Sep 17 00:00:00 2001 From: Weiko Date: Fri, 18 Oct 2024 18:59:50 +0200 Subject: [PATCH 06/38] Fix custom index creation missing indexFieldMetadatas (#7832) ## Context Regression on custom index creation where indexFieldMetadatas were not saved properly in the DB. This is because we recently changed save() to upsert() in the indexMetadataService and upsert does not handle nesting insert properly. I'm suggesting another fix where we separate indexMetadata creation and index migration creation in 2 different functions. Since the goal was to be able to recreate the index after being deleted when we changed the tsvector expression and indexMetadata was actually not deleted, we didn't need to recreate that part (hence the upsert) and only needed to run a migration to create the actual index in the workspace schema. I've updated the different services and now only call createIndexMigration when we update a search vector expression. Note: this is also fixing the sync-metadata command when running on a workspace with a custom object (including the seeded workspace which has the 'rocket' custom object), failing due to the missing 'searchVector' indexFieldMetadata --- .../index-metadata/index-metadata.service.ts | 84 +++++++++++++------ .../relation-metadata.service.ts | 2 +- .../metadata-modules/search/search.service.ts | 4 +- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.service.ts b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.service.ts index 1d75cbd7ad3f..6b8ff8fcb7c0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'class-validator'; -import { InsertResult, Repository } from 'typeorm'; +import { Repository } from 'typeorm'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { @@ -28,7 +28,7 @@ export class IndexMetadataService { private readonly workspaceMigrationService: WorkspaceMigrationService, ) {} - async createIndex( + async createIndexMetadata( workspaceId: string, objectMetadata: ObjectMetadataEntity, fieldMetadataToIndex: Partial[], @@ -45,42 +45,76 @@ export class IndexMetadataService { const indexName = `IDX_${generateDeterministicIndexName([tableName, ...columnNames])}`; - let result: InsertResult; + let result: IndexMetadataEntity; - try { - result = await this.indexMetadataRepository.upsert( - { - name: indexName, - indexFieldMetadatas: fieldMetadataToIndex.map( - (fieldMetadata, index) => { - return { - fieldMetadataId: fieldMetadata.id, - order: index, - }; - }, - ), - workspaceId, - objectMetadataId: objectMetadata.id, - ...(isDefined(indexType) ? { indexType: indexType } : {}), - isCustom: isCustom, - }, - { - conflictPaths: ['workspaceId', 'name', 'objectMetadataId'], - skipUpdateIfNoValuesChanged: true, - }, + const existingIndex = await this.indexMetadataRepository.findOne({ + where: { + name: indexName, + workspaceId, + objectMetadataId: objectMetadata.id, + }, + }); + + if (existingIndex) { + throw new Error( + `Index ${indexName} on object metadata ${objectMetadata.nameSingular} already exists`, ); + } + + try { + result = await this.indexMetadataRepository.save({ + name: indexName, + indexFieldMetadatas: fieldMetadataToIndex.map( + (fieldMetadata, index) => ({ + fieldMetadataId: fieldMetadata.id, + order: index, + }), + ), + workspaceId, + objectMetadataId: objectMetadata.id, + ...(isDefined(indexType) ? { indexType } : {}), + isCustom, + }); } catch (error) { throw new Error( `Failed to create index ${indexName} on object metadata ${objectMetadata.nameSingular}`, ); } - if (!result.identifiers.length) { + if (!result) { throw new Error( `Failed to return saved index ${indexName} on object metadata ${objectMetadata.nameSingular}`, ); } + await this.createIndexCreationMigration( + workspaceId, + objectMetadata, + fieldMetadataToIndex, + isUnique, + isCustom, + indexType, + indexWhereClause, + ); + } + + async createIndexCreationMigration( + workspaceId: string, + objectMetadata: ObjectMetadataEntity, + fieldMetadataToIndex: Partial[], + isUnique: boolean, + isCustom: boolean, + indexType?: IndexType, + indexWhereClause?: string, + ) { + const tableName = computeObjectTargetTable(objectMetadata); + + const columnNames: string[] = fieldMetadataToIndex.map( + (fieldMetadata) => fieldMetadata.name as string, + ); + + const indexName = `IDX_${generateDeterministicIndexName([tableName, ...columnNames])}`; + const migration = { name: tableName, action: WorkspaceMigrationTableActionType.ALTER_INDEXES, diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts index 90291ad6522a..d9a1850a5df6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts @@ -149,7 +149,7 @@ export class RelationMetadataService extends TypeOrmQueryService Date: Sat, 19 Oct 2024 00:39:10 +0200 Subject: [PATCH 07/38] Refactoring show page (#7838) @ehconitin following your question I did a quick refactoring of the show page - we can push it much further but it would be better to start from this code than from main Edit: I will merge to avoid conflicts, this is very far from perfect but still much better than the mess we had before --- .../components/TimelineCreateButtonGroup.tsx | 2 +- .../record-show/components/FieldsCard.tsx | 188 ++++++++++ .../components/RecordShowContainer.tsx | 322 +----------------- .../record-show/components/SummaryCard.tsx | 100 ++++++ .../hooks/useRecordShowContainerActions.ts | 66 ++++ .../hooks/useRecordShowContainerData.ts | 57 ++++ .../hooks/useRecordShowContainerTabs.ts | 110 ++++++ ...Container.tsx => ShowPageSubContainer.tsx} | 213 ++++-------- .../ui/layout/tab/components/TabList.tsx | 2 +- 9 files changed, 600 insertions(+), 460 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-show/components/FieldsCard.tsx create mode 100644 packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx create mode 100644 packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerActions.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerData.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerTabs.ts rename packages/twenty-front/src/modules/ui/layout/show-page/components/{ShowPageRightContainer.tsx => ShowPageSubContainer.tsx} (59%) diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineCreateButtonGroup.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineCreateButtonGroup.tsx index 2889dfc77c0e..4e8ec1c647cc 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineCreateButtonGroup.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineCreateButtonGroup.tsx @@ -3,7 +3,7 @@ import { IconCheckbox, IconNotes, IconPaperclip } from 'twenty-ui'; import { Button } from '@/ui/input/button/components/Button'; import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup'; -import { TAB_LIST_COMPONENT_ID } from '@/ui/layout/show-page/components/ShowPageRightContainer'; +import { TAB_LIST_COMPONENT_ID } from '@/ui/layout/show-page/components/ShowPageSubContainer'; import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; export const TimelineCreateButtonGroup = ({ diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/FieldsCard.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/FieldsCard.tsx new file mode 100644 index 000000000000..22f77e501dd8 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/components/FieldsCard.tsx @@ -0,0 +1,188 @@ +import groupBy from 'lodash.groupby'; + +import { ActivityTargetsInlineCell } from '@/activities/inline-cell/components/ActivityTargetsInlineCell'; +import { Note } from '@/activities/types/Note'; +import { Task } from '@/activities/types/Task'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; +import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox'; +import { PropertyBoxSkeletonLoader } from '@/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader'; +import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope'; +import { useRecordShowContainerActions } from '@/object-record/record-show/hooks/useRecordShowContainerActions'; +import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData'; +import { RecordDetailDuplicatesSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection'; +import { RecordDetailRelationSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSection'; +import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported'; +import { FieldMetadataType } from '~/generated/graphql'; +import { isDefined } from '~/utils/isDefined'; + +type FieldsCardProps = { + objectNameSingular: string; + objectRecordId: string; +}; + +export const FieldsCard = ({ + objectNameSingular, + objectRecordId, +}: FieldsCardProps) => { + const { + recordFromStore, + recordLoading, + objectMetadataItem, + labelIdentifierFieldMetadataItem, + isPrefetchLoading, + objectMetadataItems, + } = useRecordShowContainerData({ + objectNameSingular, + objectRecordId, + }); + + const { useUpdateOneObjectRecordMutation } = useRecordShowContainerActions({ + objectNameSingular, + objectRecordId, + recordFromStore, + }); + + const availableFieldMetadataItems = objectMetadataItem.fields + .filter( + (fieldMetadataItem) => + isFieldCellSupported(fieldMetadataItem, objectMetadataItems) && + fieldMetadataItem.id !== labelIdentifierFieldMetadataItem?.id, + ) + .sort((fieldMetadataItemA, fieldMetadataItemB) => + fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name), + ); + + const { inlineFieldMetadataItems, relationFieldMetadataItems } = groupBy( + availableFieldMetadataItems.filter( + (fieldMetadataItem) => + fieldMetadataItem.name !== 'createdAt' && + fieldMetadataItem.name !== 'deletedAt', + ), + (fieldMetadataItem) => + fieldMetadataItem.type === FieldMetadataType.Relation + ? 'relationFieldMetadataItems' + : 'inlineFieldMetadataItems', + ); + + const inlineRelationFieldMetadataItems = relationFieldMetadataItems?.filter( + (fieldMetadataItem) => + (objectNameSingular === CoreObjectNameSingular.Note && + fieldMetadataItem.name === 'noteTargets') || + (objectNameSingular === CoreObjectNameSingular.Task && + fieldMetadataItem.name === 'taskTargets'), + ); + + const boxedRelationFieldMetadataItems = relationFieldMetadataItems?.filter( + (fieldMetadataItem) => + objectNameSingular !== CoreObjectNameSingular.Note && + fieldMetadataItem.name !== 'noteTargets' && + objectNameSingular !== CoreObjectNameSingular.Task && + fieldMetadataItem.name !== 'taskTargets', + ); + const isReadOnly = objectMetadataItem.isRemote; + + return ( + <> + {isDefined(recordFromStore) && ( + <> + + {isPrefetchLoading ? ( + + ) : ( + <> + {inlineRelationFieldMetadataItems?.map( + (fieldMetadataItem, index) => ( + + + + ), + )} + {inlineFieldMetadataItems?.map((fieldMetadataItem, index) => ( + + + + ))} + + )} + + + {boxedRelationFieldMetadataItems?.map((fieldMetadataItem, index) => ( + + + + ))} + + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx index 9b1e10601ab4..8e911edac10c 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx @@ -1,47 +1,10 @@ -import groupBy from 'lodash.groupby'; -import { useRecoilState, useRecoilValue } from 'recoil'; - -import { ActivityTargetsInlineCell } from '@/activities/inline-cell/components/ActivityTargetsInlineCell'; -import { Note } from '@/activities/types/Note'; -import { Task } from '@/activities/types/Task'; import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord'; -import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon'; -import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; -import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; -import { - FieldContext, - RecordUpdateHook, - RecordUpdateHookParams, -} from '@/object-record/record-field/contexts/FieldContext'; -import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; -import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox'; -import { PropertyBoxSkeletonLoader } from '@/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader'; -import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope'; -import { RecordDetailDuplicatesSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection'; -import { RecordDetailRelationSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSection'; -import { recordLoadingFamilyState } from '@/object-record/record-store/states/recordLoadingFamilyState'; -import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { recordStoreIdentifierFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifierSelector'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported'; -import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; import { ShowPageContainer } from '@/ui/layout/page/ShowPageContainer'; -import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer'; -import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer'; -import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard'; -import { ShowPageSummaryCardSkeletonLoader } from '@/ui/layout/show-page/components/ShowPageSummaryCardSkeletonLoader'; -import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { - FieldMetadataType, - FileFolder, - useUploadImageMutation, -} from '~/generated/graphql'; -import { isDefined } from '~/utils/isDefined'; -import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; + +import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData'; +import { useRecordShowContainerTabs } from '@/object-record/record-show/hooks/useRecordShowContainerTabs'; +import { ShowPageSubContainer } from '@/ui/layout/show-page/components/ShowPageSubContainer'; type RecordShowContainerProps = { objectNameSingular: string; @@ -58,261 +21,20 @@ export const RecordShowContainer = ({ isInRightDrawer = false, isNewRightDrawerItemLoading = false, }: RecordShowContainerProps) => { - const { objectMetadataItem } = useObjectMetadataItem({ + const { + recordFromStore, + objectMetadataItem, + isPrefetchLoading, + recordLoading, + } = useRecordShowContainerData({ objectNameSingular, + objectRecordId, }); - const { objectMetadataItems } = useObjectMetadataItems(); - - const { labelIdentifierFieldMetadataItem } = - useLabelIdentifierFieldMetadataItem({ - objectNameSingular, - }); - - const [recordLoading] = useRecoilState( - recordLoadingFamilyState(objectRecordId), - ); - - const [recordFromStore] = useRecoilState( - recordStoreFamilyState(objectRecordId), - ); - - const recordIdentifier = useRecoilValue( - recordStoreIdentifierFamilySelector({ - objectNameSingular, - recordId: objectRecordId, - }), - ); - const [uploadImage] = useUploadImageMutation(); - const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular }); - - const useUpdateOneObjectRecordMutation: RecordUpdateHook = () => { - const updateEntity = ({ variables }: RecordUpdateHookParams) => { - updateOneRecord?.({ - idToUpdate: variables.where.id as string, - updateOneRecordInput: variables.updateOneRecordInput, - }); - }; - - return [updateEntity, { loading: false }]; - }; - - const onUploadPicture = async (file: File) => { - if (objectNameSingular !== 'person') { - return; - } - - const result = await uploadImage({ - variables: { - file, - fileFolder: FileFolder.PersonPicture, - }, - }); - - const avatarUrl = result?.data?.uploadImage; - - if (!avatarUrl || isUndefinedOrNull(updateOneRecord) || !recordFromStore) { - return; - } - - await updateOneRecord({ - idToUpdate: objectRecordId, - updateOneRecordInput: { - avatarUrl, - }, - }); - }; - - const availableFieldMetadataItems = objectMetadataItem.fields - .filter( - (fieldMetadataItem) => - isFieldCellSupported(fieldMetadataItem, objectMetadataItems) && - fieldMetadataItem.id !== labelIdentifierFieldMetadataItem?.id, - ) - .sort((fieldMetadataItemA, fieldMetadataItemB) => - fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name), - ); - - const { inlineFieldMetadataItems, relationFieldMetadataItems } = groupBy( - availableFieldMetadataItems.filter( - (fieldMetadataItem) => - fieldMetadataItem.name !== 'createdAt' && - fieldMetadataItem.name !== 'deletedAt', - ), - (fieldMetadataItem) => - fieldMetadataItem.type === FieldMetadataType.Relation - ? 'relationFieldMetadataItems' - : 'inlineFieldMetadataItems', - ); - - const inlineRelationFieldMetadataItems = relationFieldMetadataItems?.filter( - (fieldMetadataItem) => - (objectNameSingular === CoreObjectNameSingular.Note && - fieldMetadataItem.name === 'noteTargets') || - (objectNameSingular === CoreObjectNameSingular.Task && - fieldMetadataItem.name === 'taskTargets'), - ); - - const boxedRelationFieldMetadataItems = relationFieldMetadataItems?.filter( - (fieldMetadataItem) => - objectNameSingular !== CoreObjectNameSingular.Note && - fieldMetadataItem.name !== 'noteTargets' && - objectNameSingular !== CoreObjectNameSingular.Task && - fieldMetadataItem.name !== 'taskTargets', - ); - const { Icon, IconColor } = useGetStandardObjectIcon(objectNameSingular); - const isReadOnly = objectMetadataItem.isRemote; - const isMobile = useIsMobile() || isInRightDrawer; - const isPrefetchLoading = useIsPrefetchLoading(); - - const summaryCard = - !isNewRightDrawerItemLoading && isDefined(recordFromStore) ? ( - - - - } - avatarType={recordIdentifier?.avatarType ?? 'rounded'} - onUploadPicture={ - objectNameSingular === 'person' ? onUploadPicture : undefined - } - /> - ) : ( - - ); - - const fieldsBox = ( - <> - {isDefined(recordFromStore) && ( - <> - - {isPrefetchLoading ? ( - - ) : ( - <> - {inlineRelationFieldMetadataItems?.map( - (fieldMetadataItem, index) => ( - - - - ), - )} - {inlineFieldMetadataItems?.map((fieldMetadataItem, index) => ( - - - - ))} - - )} - - - {boxedRelationFieldMetadataItems?.map((fieldMetadataItem, index) => ( - - - - ))} - - )} - + const tabs = useRecordShowContainerTabs( + loading, + objectNameSingular as CoreObjectNameSingular, + isInRightDrawer, ); return ( @@ -324,23 +46,15 @@ export const RecordShowContainer = ({ /> )} - - {!isMobile && summaryCard} - {!isMobile && fieldsBox} - - } - fieldsBox={fieldsBox} loading={isPrefetchLoading || loading || recordLoading} + isNewRightDrawerItemLoading={isNewRightDrawerItemLoading} /> diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx new file mode 100644 index 000000000000..05b76a1e939c --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx @@ -0,0 +1,100 @@ +import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; +import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope'; +import { useRecordShowContainerActions } from '@/object-record/record-show/hooks/useRecordShowContainerActions'; +import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData'; +import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard'; +import { ShowPageSummaryCardSkeletonLoader } from '@/ui/layout/show-page/components/ShowPageSummaryCardSkeletonLoader'; +import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import { FieldMetadataType } from '~/generated/graphql'; +import { isDefined } from '~/utils/isDefined'; + +type SummaryCardProps = { + objectNameSingular: string; + objectRecordId: string; + isNewRightDrawerItemLoading: boolean; + isInRightDrawer: boolean; +}; + +export const SummaryCard = ({ + objectNameSingular, + objectRecordId, + isNewRightDrawerItemLoading, + isInRightDrawer, +}: SummaryCardProps) => { + const { + recordFromStore, + recordLoading, + objectMetadataItem, + labelIdentifierFieldMetadataItem, + isPrefetchLoading, + recordIdentifier, + } = useRecordShowContainerData({ + objectNameSingular, + objectRecordId, + }); + + const { onUploadPicture, useUpdateOneObjectRecordMutation } = + useRecordShowContainerActions({ + objectNameSingular, + objectRecordId, + recordFromStore, + }); + + const { Icon, IconColor } = useGetStandardObjectIcon(objectNameSingular); + const isMobile = useIsMobile() || isInRightDrawer; + const isReadOnly = objectMetadataItem.isRemote; + + if (isNewRightDrawerItemLoading || !isDefined(recordFromStore)) { + return ; + } + + return ( + + + + } + avatarType={recordIdentifier?.avatarType ?? 'rounded'} + onUploadPicture={ + objectNameSingular === CoreObjectNameSingular.Person + ? onUploadPicture + : undefined + } + /> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerActions.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerActions.ts new file mode 100644 index 000000000000..0188f48f696f --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerActions.ts @@ -0,0 +1,66 @@ +import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; +import { + RecordUpdateHook, + RecordUpdateHookParams, +} from '@/object-record/record-field/contexts/FieldContext'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { FileFolder } from '~/generated-metadata/graphql'; +import { useUploadImageMutation } from '~/generated/graphql'; +import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; + +interface UseRecordShowContainerActionsProps { + objectNameSingular: string; + objectRecordId: string; + recordFromStore: ObjectRecord | null; +} + +export const useRecordShowContainerActions = ({ + objectNameSingular, + objectRecordId, + recordFromStore, +}: UseRecordShowContainerActionsProps) => { + const [uploadImage] = useUploadImageMutation(); + const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular }); + + const useUpdateOneObjectRecordMutation: RecordUpdateHook = () => { + const updateEntity = ({ variables }: RecordUpdateHookParams) => { + updateOneRecord?.({ + idToUpdate: variables.where.id as string, + updateOneRecordInput: variables.updateOneRecordInput, + }); + }; + + return [updateEntity, { loading: false }]; + }; + + const onUploadPicture = async (file: File) => { + if (objectNameSingular !== 'person') { + return; + } + + const result = await uploadImage({ + variables: { + file, + fileFolder: FileFolder.PersonPicture, + }, + }); + + const avatarUrl = result?.data?.uploadImage; + + if (!avatarUrl || isUndefinedOrNull(updateOneRecord) || !recordFromStore) { + return; + } + + await updateOneRecord({ + idToUpdate: objectRecordId, + updateOneRecordInput: { + avatarUrl, + }, + }); + }; + + return { + onUploadPicture, + useUpdateOneObjectRecordMutation, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerData.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerData.ts new file mode 100644 index 000000000000..15eeb056bab5 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerData.ts @@ -0,0 +1,57 @@ +import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; +import { recordLoadingFamilyState } from '@/object-record/record-store/states/recordLoadingFamilyState'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { recordStoreIdentifierFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifierSelector'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; +import { useRecoilState, useRecoilValue } from 'recoil'; + +type UseRecordShowContainerDataProps = { + objectNameSingular: string; + objectRecordId: string; +}; + +export const useRecordShowContainerData = ({ + objectNameSingular, + objectRecordId, +}: UseRecordShowContainerDataProps) => { + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const { labelIdentifierFieldMetadataItem } = + useLabelIdentifierFieldMetadataItem({ + objectNameSingular, + }); + + const [recordLoading] = useRecoilState( + recordLoadingFamilyState(objectRecordId), + ); + + const [recordFromStore] = useRecoilState( + recordStoreFamilyState(objectRecordId), + ); + + const recordIdentifier = useRecoilValue( + recordStoreIdentifierFamilySelector({ + objectNameSingular, + recordId: objectRecordId, + }), + ); + + const isPrefetchLoading = useIsPrefetchLoading(); + + const { objectMetadataItems } = useObjectMetadataItems(); + + return { + recordFromStore, + recordLoading, + objectMetadataItem, + labelIdentifierFieldMetadataItem, + isPrefetchLoading, + recordIdentifier, + objectMetadataItems, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerTabs.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerTabs.ts new file mode 100644 index 000000000000..1d029f4877f8 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerTabs.ts @@ -0,0 +1,110 @@ +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; +import { + IconCalendarEvent, + IconCheckbox, + IconList, + IconMail, + IconNotes, + IconPaperclip, + IconSettings, + IconTimelineEvent, +} from 'twenty-ui'; + +export const useRecordShowContainerTabs = ( + loading: boolean, + targetObjectNameSingular: CoreObjectNameSingular, + isInRightDrawer: boolean, +) => { + const isMobile = useIsMobile(); + const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED'); + + const isWorkflow = + isWorkflowEnabled && + targetObjectNameSingular === CoreObjectNameSingular.Workflow; + const isWorkflowVersion = + isWorkflowEnabled && + targetObjectNameSingular === CoreObjectNameSingular.WorkflowVersion; + + const isCompanyOrPerson = [ + CoreObjectNameSingular.Company, + CoreObjectNameSingular.Person, + ].includes(targetObjectNameSingular); + const shouldDisplayCalendarTab = isCompanyOrPerson; + const shouldDisplayEmailsTab = isCompanyOrPerson; + + return [ + { + id: 'richText', + title: 'Note', + Icon: IconNotes, + hide: + loading || + (targetObjectNameSingular !== CoreObjectNameSingular.Note && + targetObjectNameSingular !== CoreObjectNameSingular.Task), + }, + { + id: 'fields', + title: 'Fields', + Icon: IconList, + hide: !(isMobile || isInRightDrawer), + }, + { + id: 'timeline', + title: 'Timeline', + Icon: IconTimelineEvent, + hide: isInRightDrawer || isWorkflow || isWorkflowVersion, + }, + { + id: 'tasks', + title: 'Tasks', + Icon: IconCheckbox, + hide: + targetObjectNameSingular === CoreObjectNameSingular.Note || + targetObjectNameSingular === CoreObjectNameSingular.Task || + isWorkflow || + isWorkflowVersion, + }, + { + id: 'notes', + title: 'Notes', + Icon: IconNotes, + hide: + targetObjectNameSingular === CoreObjectNameSingular.Note || + targetObjectNameSingular === CoreObjectNameSingular.Task || + isWorkflow || + isWorkflowVersion, + }, + { + id: 'files', + title: 'Files', + Icon: IconPaperclip, + hide: isWorkflow || isWorkflowVersion, + }, + { + id: 'emails', + title: 'Emails', + Icon: IconMail, + hide: !shouldDisplayEmailsTab, + }, + { + id: 'calendar', + title: 'Calendar', + Icon: IconCalendarEvent, + hide: !shouldDisplayCalendarTab, + }, + { + id: 'workflow', + title: 'Workflow', + Icon: IconSettings, + hide: !isWorkflow, + }, + { + id: 'workflowVersion', + title: 'Workflow Version', + Icon: IconSettings, + hide: !isWorkflowVersion, + }, + ]; +}; diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx similarity index 59% rename from packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx rename to packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx index 449963c0135b..017f38fd9280 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx @@ -8,32 +8,24 @@ import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableE import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading'; +import { FieldsCard } from '@/object-record/record-show/components/FieldsCard'; +import { SummaryCard } from '@/object-record/record-show/components/SummaryCard'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { Button } from '@/ui/input/button/components/Button'; import { ShowPageActivityContainer } from '@/ui/layout/show-page/components/ShowPageActivityContainer'; -import { TabList } from '@/ui/layout/tab/components/TabList'; +import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer'; +import { SingleTabProps, TabList } from '@/ui/layout/tab/components/TabList'; import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { WorkflowVersionVisualizer } from '@/workflow/components/WorkflowVersionVisualizer'; import { WorkflowVersionVisualizerEffect } from '@/workflow/components/WorkflowVersionVisualizerEffect'; import { WorkflowVisualizer } from '@/workflow/components/WorkflowVisualizer'; import { WorkflowVisualizerEffect } from '@/workflow/components/WorkflowVisualizerEffect'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import styled from '@emotion/styled'; import { useState } from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; -import { - IconCalendarEvent, - IconCheckbox, - IconList, - IconMail, - IconNotes, - IconPaperclip, - IconSettings, - IconTimelineEvent, - IconTrash, -} from 'twenty-ui'; +import { IconTrash } from 'twenty-ui'; const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>` display: flex; @@ -89,145 +81,51 @@ const StyledContentContainer = styled.div<{ isInRightDrawer: boolean }>` export const TAB_LIST_COMPONENT_ID = 'show-page-right-tab-list'; -type ShowPageRightContainerProps = { +type ShowPageSubContainerProps = { + tabs: SingleTabProps[]; targetableObject: Pick< ActivityTargetableObject, 'targetObjectNameSingular' | 'id' >; - timeline?: boolean; - tasks?: boolean; - notes?: boolean; - emails?: boolean; - fieldsBox?: JSX.Element; - summaryCard?: JSX.Element; isInRightDrawer?: boolean; loading: boolean; + isNewRightDrawerItemLoading?: boolean; }; -export const ShowPageRightContainer = ({ +export const ShowPageSubContainer = ({ + tabs, targetableObject, - timeline, - tasks, - notes, - emails, loading, - fieldsBox, - summaryCard, isInRightDrawer = false, -}: ShowPageRightContainerProps) => { + isNewRightDrawerItemLoading = false, +}: ShowPageSubContainerProps) => { const { activeTabIdState } = useTabList( `${TAB_LIST_COMPONENT_ID}-${isInRightDrawer}`, ); const activeTabId = useRecoilValue(activeTabIdState); - const targetObjectNameSingular = - targetableObject.targetObjectNameSingular as CoreObjectNameSingular; - - const isCompanyOrPerson = [ - CoreObjectNameSingular.Company, - CoreObjectNameSingular.Person, - ].includes(targetObjectNameSingular); - - const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED'); - const isWorkflow = - isWorkflowEnabled && - targetableObject.targetObjectNameSingular === - CoreObjectNameSingular.Workflow; - const isWorkflowVersion = - isWorkflowEnabled && - targetableObject.targetObjectNameSingular === - CoreObjectNameSingular.WorkflowVersion; - - const shouldDisplayCalendarTab = isCompanyOrPerson; - const shouldDisplayEmailsTab = emails && isCompanyOrPerson; - const isMobile = useIsMobile(); const isNewViewableRecordLoading = useRecoilValue( isNewViewableRecordLoadingState, ); - const tabs = [ - { - id: 'richText', - title: 'Note', - Icon: IconNotes, - hide: - loading || - (targetableObject.targetObjectNameSingular !== - CoreObjectNameSingular.Note && - targetableObject.targetObjectNameSingular !== - CoreObjectNameSingular.Task), - }, - { - id: 'fields', - title: 'Fields', - Icon: IconList, - hide: !(isMobile || isInRightDrawer), - }, - { - id: 'timeline', - title: 'Timeline', - Icon: IconTimelineEvent, - hide: !timeline || isInRightDrawer || isWorkflow || isWorkflowVersion, - }, - { - id: 'tasks', - title: 'Tasks', - Icon: IconCheckbox, - hide: - !tasks || - targetableObject.targetObjectNameSingular === - CoreObjectNameSingular.Note || - targetableObject.targetObjectNameSingular === - CoreObjectNameSingular.Task || - isWorkflow || - isWorkflowVersion, - }, - { - id: 'notes', - title: 'Notes', - Icon: IconNotes, - hide: - !notes || - targetableObject.targetObjectNameSingular === - CoreObjectNameSingular.Note || - targetableObject.targetObjectNameSingular === - CoreObjectNameSingular.Task || - isWorkflow || - isWorkflowVersion, - }, - { - id: 'files', - title: 'Files', - Icon: IconPaperclip, - hide: !notes || isWorkflow || isWorkflowVersion, - }, - { - id: 'emails', - title: 'Emails', - Icon: IconMail, - hide: !shouldDisplayEmailsTab, - }, - { - id: 'calendar', - title: 'Calendar', - Icon: IconCalendarEvent, - hide: !shouldDisplayCalendarTab, - }, - { - id: 'workflow', - title: 'Workflow', - Icon: IconSettings, - hide: !isWorkflow, - }, - { - id: 'workflowVersion', - title: 'Workflow Version', - Icon: IconSettings, - hide: !isWorkflowVersion, - }, - ]; + const summaryCard = ( + + ); + + const fieldsCard = ( + + ); + const renderActiveTabContent = () => { switch (activeTabId) { case 'timeline': @@ -251,10 +149,9 @@ export const ShowPageRightContainer = ({ case 'fields': return ( - {fieldsBox} + {fieldsCard} ); - case 'tasks': return ; case 'notes': @@ -307,28 +204,36 @@ export const ShowPageRightContainer = ({ ); return ( - - - - - {summaryCard} - - {renderActiveTabContent()} - - {isInRightDrawer && recordFromStore && !recordFromStore.deletedAt && ( - - - + <> + {!isMobile && !isInRightDrawer && ( + + {summaryCard} + {fieldsCard} + )} - + + + + + {(isMobile || isInRightDrawer) && summaryCard} + + {renderActiveTabContent()} + + {isInRightDrawer && recordFromStore && !recordFromStore.deletedAt && ( + + + + )} + + ); }; diff --git a/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx b/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx index c66767a09039..8375cc0825fe 100644 --- a/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx +++ b/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx @@ -9,7 +9,7 @@ import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { Tab } from './Tab'; -type SingleTabProps = { +export type SingleTabProps = { title: string; Icon?: IconComponent; id: string; From 29f903a83b540e56944bcbad1caf128e8781e2ca Mon Sep 17 00:00:00 2001 From: Prashant Acharya <125622593+prashant48653c@users.noreply.github.com> Date: Sat, 19 Oct 2024 14:43:20 +0545 Subject: [PATCH 08/38] Added new logo images (#7840) **Added new logo in different png format** Fixed Issue: Design a new logo for Twenty (300 points) #**7834** What tool did I used? I used logo.com as a design tool to design the logo. Logo I made: ![20-high-resolution-logo-black](https://github.com/user-attachments/assets/f041d22d-6d7f-4171-96b7-302a255e89e9) ![20-high-resolution-logo-white-transparent](https://github.com/user-attachments/assets/163f1b9d-cfa2-4d75-ba9d-9cb0ce54bf46) ![20-high-resolution-logo-black-transparent](https://github.com/user-attachments/assets/4648107d-c628-4a64-9bd1-94ab036c4b60) ![20-high-resolution-logo](https://github.com/user-attachments/assets/7735e623-b2e2-4484-b71c-5fc42be33362) --- ...0-high-resolution-logo-black-transparent.png | Bin 0 -> 44376 bytes .../logos/20-high-resolution-logo-black.png | Bin 0 -> 21963 bytes ...0-high-resolution-logo-white-transparent.png | Bin 0 -> 44370 bytes .../public/logos/20-high-resolution-logo.png | Bin 0 -> 20740 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/twenty-front/public/logos/20-high-resolution-logo-black-transparent.png create mode 100644 packages/twenty-front/public/logos/20-high-resolution-logo-black.png create mode 100644 packages/twenty-front/public/logos/20-high-resolution-logo-white-transparent.png create mode 100644 packages/twenty-front/public/logos/20-high-resolution-logo.png diff --git a/packages/twenty-front/public/logos/20-high-resolution-logo-black-transparent.png b/packages/twenty-front/public/logos/20-high-resolution-logo-black-transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..236da7815022be7f5882055778dca43461420312 GIT binary patch literal 44376 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 z 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¬veSl>h6#Rwdpkj~I&A_0hd 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%0Atq&e| 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-front/public/logos/20-high-resolution-logo-black.png b/packages/twenty-front/public/logos/20-high-resolution-logo-black.png new file mode 100644 index 0000000000000000000000000000000000000000..db41f79831e503a772cebc727e5b7c6d9b248969 GIT binary patch literal 21963 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 Rib$PL`{^i?cx34G>{FF>mn{Nv`9X?QpnSaW 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 GBmNI0RyfH3 literal 0 HcmV?d00001 diff --git a/packages/twenty-front/public/logos/20-high-resolution-logo.png b/packages/twenty-front/public/logos/20-high-resolution-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0dbe8de6cba14a3bdeb246f740ce57c3dbbaa05f GIT binary patch literal 20740 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 literal 0 HcmV?d00001 From 36e59d80c488bb46b9a3ab4303d0035222f3810f Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Sat, 19 Oct 2024 10:59:04 +0200 Subject: [PATCH 09/38] Use the correct color for workflow nodes label (#7829) Follow the design from the Figma about the color to use. Big up to @Bonapara for doing great job on the Figma! It was done on stream! Fixes #7058 --- .../workflow/components/WorkflowDiagramBaseStepNode.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramBaseStepNode.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramBaseStepNode.tsx index 8484a29e7eaf..9d8c6b39b303 100644 --- a/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramBaseStepNode.tsx +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramBaseStepNode.tsx @@ -66,7 +66,9 @@ const StyledStepNodeLabel = styled.div<{ variant?: Variant }>` font-weight: ${({ theme }) => theme.font.weight.medium}; column-gap: ${({ theme }) => theme.spacing(2)}; color: ${({ variant, theme }) => - variant === 'placeholder' ? theme.font.color.extraLight : null}; + variant === 'placeholder' + ? theme.font.color.extraLight + : theme.font.color.primary}; `; const StyledSourceHandle = styled(Handle)` From 8368f14fb913c1aaea0c6173570a691bbd0b9887 Mon Sep 17 00:00:00 2001 From: Anis Hamal <73131641+AndrewHamal@users.noreply.github.com> Date: Sat, 19 Oct 2024 15:27:43 +0545 Subject: [PATCH 10/38] Bug Fix: Decreased border radius of badge and changed badge parent div padding to margin (#7835) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What does this PR do? Decreased the border-radius of the badge and changed the padding-top and padding-bottom of the badge parent div to margin-top and margin-bottom Fixes #7811 Screenshot 2024-10-19 at 12 27 49 AM Screenshot 2024-10-19 at 12 28 37 AM ## How should this be tested? Create any task, notes, or files. --------- Co-authored-by: ehconitin --- .../timelineActivities/components/EventsGroup.tsx | 6 +++--- .../ui/layout/show-page/components/ShowPageSubContainer.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventsGroup.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/components/EventsGroup.tsx index 430968f4f259..fe368ae9bab9 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventsGroup.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/components/EventsGroup.tsx @@ -20,8 +20,8 @@ const StyledActivityGroup = styled.div` `; const StyledActivityGroupContainer = styled.div` - padding-bottom: ${({ theme }) => theme.spacing(2)}; - padding-top: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${({ theme }) => theme.spacing(3)}; + margin-top: ${({ theme }) => theme.spacing(3)}; position: relative; `; @@ -29,7 +29,7 @@ const StyledActivityGroupBar = styled.div` align-items: center; background: ${({ theme }) => theme.background.secondary}; border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.xl}; + border-radius: ${({ theme }) => theme.border.radius.md}; display: flex; flex-direction: column; height: 100%; diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx index 017f38fd9280..d8bf449d6afd 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx @@ -61,13 +61,13 @@ const StyledGreyBox = styled.div<{ isInRightDrawer: boolean }>` const StyledButtonContainer = styled.div` align-items: center; - bottom: 0; + background: ${({ theme }) => theme.background.secondary}; border-top: 1px solid ${({ theme }) => theme.border.color.light}; + bottom: 0; + box-sizing: border-box; display: flex; justify-content: flex-end; padding: ${({ theme }) => theme.spacing(2)}; - width: 100%; - box-sizing: border-box; position: absolute; width: 100%; `; From ac88840bf040a2a1bf825484f1909ca530330b39 Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras <65061890+Nabhag8848@users.noreply.github.com> Date: Sat, 19 Oct 2024 20:52:47 +0530 Subject: [PATCH 11/38] fix: redis url to not be optional anymore (#7850) ## Description - `REDIS_URL` is required Redis Required ---- - Closes #7849 - Might be related #7768 --- - Wasn't gracefully reseting database ``` npx nx database:reset twenty-server ``` --- packages/twenty-server/.env.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/twenty-server/.env.example b/packages/twenty-server/.env.example index f43d3ed7bca3..0b520154c4eb 100644 --- a/packages/twenty-server/.env.example +++ b/packages/twenty-server/.env.example @@ -8,6 +8,8 @@ LOGIN_TOKEN_SECRET=replace_me_with_a_random_string_login REFRESH_TOKEN_SECRET=replace_me_with_a_random_string_refresh FILE_TOKEN_SECRET=replace_me_with_a_random_string_refresh SIGN_IN_PREFILLED=true +REDIS_URL=redis://localhost:6379 + # ———————— Optional ———————— # PORT=3000 @@ -50,7 +52,6 @@ SIGN_IN_PREFILLED=true # SENTRY_FRONT_DSN=https://xxx@xxx.ingest.sentry.io/xxx # LOG_LEVELS=error,warn # MESSAGE_QUEUE_TYPE=pg-boss -# REDIS_URL=redis://localhost:6379 # DEMO_WORKSPACE_IDS=REPLACE_ME_WITH_A_RANDOM_UUID # SERVER_URL=http://localhost:3000 # WORKSPACE_INACTIVE_DAYS_BEFORE_NOTIFICATION=30 From c5138df58c94a8a9f916d51004bebf8ca57d9a1b Mon Sep 17 00:00:00 2001 From: sateshcharan Date: Sun, 20 Oct 2024 11:27:05 +0530 Subject: [PATCH 12/38] oss.gg side-quest-gif-magic completed (#7873) ![image](https://github.com/user-attachments/assets/3238d111-9098-4e60-a287-87d7f13f2ace) --- oss-gg/twenty-side-quest/5-gif-magic.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oss-gg/twenty-side-quest/5-gif-magic.md b/oss-gg/twenty-side-quest/5-gif-magic.md index 320ffa9015db..b55bc24fc838 100644 --- a/oss-gg/twenty-side-quest/5-gif-magic.md +++ b/oss-gg/twenty-side-quest/5-gif-magic.md @@ -34,4 +34,7 @@ Your turn 👇 » 16-October-2024 by Harsh Bhat » Link to gif: https://giphy.com/gifs/oss-twentycrm-mgoYSDrjIalUL7XJzm + +» 20-October-2024 by Satesh Charan +» Link to gif: https://giphy.com/gifs/rXjvGBrTqu7vvhEsvR --- From dc1fbc3315e4e4bcc2d0c51ac9e58b1eef0f5a90 Mon Sep 17 00:00:00 2001 From: Manish Kr Prasad <85901005+Naprila@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:49:42 +0530 Subject: [PATCH 13/38] Created a meme on Twenty and posted on X (#7883) ### Points: 150 ### Proof: Link to Tweet: https://x.com/mkprasad_821/status/1847900277510123706 ![Screenshot 2024-10-20 at 12 49 12 PM](https://github.com/user-attachments/assets/ae47d070-3b98-46b7-ba89-ecce8c16ae9a) Co-authored-by: Apple --- oss-gg/twenty-side-quest/4-meme-magic.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oss-gg/twenty-side-quest/4-meme-magic.md b/oss-gg/twenty-side-quest/4-meme-magic.md index 041c73ef081e..feacc0b857a7 100644 --- a/oss-gg/twenty-side-quest/4-meme-magic.md +++ b/oss-gg/twenty-side-quest/4-meme-magic.md @@ -34,4 +34,7 @@ Your turn 👇 » 16-October-2024 by Harsh Bhat » Link to Tweet: https://x.com/HarshBhatX/status/1844698253104709899 + +» 20-October-2024 by Naprila +» Link to Tweet: https://x.com/mkprasad_821/status/1847900277510123706 --- From f801f3aa9f4f3328e950ed403d46fc535d967a5e Mon Sep 17 00:00:00 2001 From: Manish Kr Prasad <85901005+Naprila@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:50:39 +0530 Subject: [PATCH 14/38] oss.gg Tweet about your favourite feature in Twenty (#7880) Point: 50 Proof: Link: https://x.com/mkprasad_821/status/1847895747707953205 Screenshot 2024-10-20 at 12 31 07 PM Co-authored-by: Apple --- oss-gg/twenty-side-quest/2-tweet-about-fav-twenty-feature.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oss-gg/twenty-side-quest/2-tweet-about-fav-twenty-feature.md b/oss-gg/twenty-side-quest/2-tweet-about-fav-twenty-feature.md index 07d2e067c708..21840593b1af 100644 --- a/oss-gg/twenty-side-quest/2-tweet-about-fav-twenty-feature.md +++ b/oss-gg/twenty-side-quest/2-tweet-about-fav-twenty-feature.md @@ -28,4 +28,7 @@ Your turn 👇 » 16-October-2024 by Harsh Bhat » Link to Tweet: https://x.com/HarshBhatX/status/1846075312691413066 + +» 20-October-2024 by Naprila +» Link to Tweet: https://x.com/mkprasad_821/status/1847895747707953205 --- From eccf0bf8ba68560fa5e01c8fdce92240e7ea0e3f Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Sun, 20 Oct 2024 20:20:19 +0200 Subject: [PATCH 15/38] Enforce front project structure through ESLINT (#7863) Fixes: https://github.com/twentyhq/twenty/issues/7329 --- .gitignore | 1 + nx.json | 2 +- package.json | 1 + packages/twenty-front/.eslintrc.cjs | 9 +- packages/twenty-front/folderStructure.json | 81 ++++++++++++++ packages/twenty-front/jest.config.ts | 4 +- packages/twenty-front/project.json | 4 +- .../blocks/{ => components}/FileBlock.tsx | 6 +- .../blocks/{schema.ts => constants/Schema.ts} | 4 +- .../{slashMenu.tsx => utils/getSlashMenu.ts} | 4 +- .../calendar/components/Calendar.tsx | 4 +- .../__stories__/Calendar.stories.tsx | 4 +- .../timelineCalendarEventFragment.ts | 3 +- ...imelineCalendarEventParticipantFragment.ts | 0 .../timelineCalendarEventWithTotalFragment.ts | 3 +- .../getTimelineCalendarEventsFromCompanyId.ts | 3 +- .../getTimelineCalendarEventsFromPersonId.ts | 3 +- .../activities/components/RichTextEditor.tsx | 4 +- .../emails/components/EmailThreads.tsx | 4 +- .../getTimelineThreadsFromCompanyId.test.ts | 0 .../getTimelineThreadsFromPersonId.test.ts | 0 .../queries/fragments/participantFragment.ts | 0 .../fragments/timelineThreadFragment.ts | 2 +- .../timelineThreadWithTotalFragment.ts | 3 +- .../getTimelineThreadsFromCompanyId.ts | 3 +- .../queries/getTimelineThreadsFromPersonId.ts | 2 +- ...efreshShowPageFindManyActivitiesQueries.ts | 2 +- .../activities/hooks/useUpsertActivity.ts | 2 +- .../activities/notes/hooks/useNotes.ts | 2 +- .../tasks/components/PageAddTaskButton.tsx | 2 +- .../__stories__/TaskGroups.stories.tsx | 0 .../__stories__/TaskList.stories.tsx | 0 .../activities/tasks/hooks/useTasks.ts | 2 +- .../components/EventList.tsx | 8 +- .../components/EventRow.tsx | 12 +- .../components/EventsGroup.tsx | 4 +- .../components/TimelineActivities.tsx | 8 +- .../components/TimelineCreateButtonGroup.tsx | 0 .../TimelineActivities.stories.tsx | 6 +- .../FindManyTimelineActivitiesOrderBy.ts | 0 .../contexts/TimelineActivityContext.ts | 0 .../__tests__/useTimelineActivities.test.tsx | 2 +- .../useLinkedObjectObjectMetadataItem.ts | 0 .../hooks/useLinkedObjectsTitle.ts | 0 .../hooks/useTimelineActivities.ts | 4 +- .../activity/components/EventRowActivity.tsx | 2 +- .../components/EventCardCalendarEvent.tsx | 0 .../components/EventRowCalendarEvent.tsx | 10 +- .../EventCardCalendarEvent.stories.tsx | 4 +- .../rows/components/EventCard.tsx | 0 .../rows/components/EventCardToggleButton.tsx | 0 .../components/EventIconDynamicComponent.tsx | 2 +- .../components/EventRowDynamicComponent.tsx | 10 +- .../main-object/components/EventFieldDiff.tsx | 6 +- .../components/EventFieldDiffContainer.tsx | 2 +- .../components/EventFieldDiffLabel.tsx | 0 .../components/EventFieldDiffValue.tsx | 0 .../components/EventFieldDiffValueEffect.tsx | 0 .../components/EventRowMainObject.tsx | 7 +- .../components/EventRowMainObjectUpdated.tsx | 12 +- .../EventRowMainObjectUpdated.stories.tsx | 4 +- .../message/components/EventCardMessage.tsx | 2 +- .../components/EventCardMessageNotShared.tsx | 0 .../message/components/EventRowMessage.tsx | 10 +- .../__stories__/EventCardMessage.stories.tsx | 6 +- .../objectShowPageTargetableObjectIdState.ts | 0 .../types/TimelineActivity.ts | 0 .../types/TimelineActivityLinkedObject.ts | 0 ...filterOutInvalidTimelineActivities.test.ts | 4 +- .../getTimelineActivityAuthorFullName.test.ts | 4 +- .../__tests__/groupEventsByMonth.test.ts | 0 .../filterOutInvalidTimelineActivities.ts | 2 +- ...lterTimelineActivityByLinkedObjectTypes.ts | 4 +- .../getTimelineActivityAuthorFullName.ts | 2 +- .../utils/groupEventsByMonth.ts | 2 +- .../modules/apollo/services/apollo.factory.ts | 2 +- ...rmat-title.test.ts => formatTitle.test.ts} | 2 +- .../apollo/utils/__tests__/utils.test.ts | 4 - .../utils/{format-title.ts => formatTitle.ts} | 0 .../apollo/utils/{index.ts => loggerLink.ts} | 2 +- .../src/modules/app/components/AppRouter.tsx | 4 +- .../app/components/AppRouterProviders.tsx | 2 +- .../useCreateAppRouter.tsx} | 6 +- .../{__test__ => __tests__}/useAuth.test.tsx | 0 .../useIsLogged.test.ts | 0 .../src/modules/auth/services/AuthService.ts | 2 +- .../passwordRegex.test.ts | 0 .../command-menu/components/CommandMenu.tsx | 2 +- .../useCommandMenu.test.tsx | 0 .../modules/favorites/hooks/useFavorites.ts | 2 +- ...ort-favorites.util.ts => sortFavorites.ts} | 0 .../ApolloMetadataClientProvider.tsx | 2 +- .../PreComputedChipGeneratorsProvider.tsx | 2 +- .../ApolloClientMetadataContext.ts | 0 .../PreComputedChipGeneratorsContext.ts | 0 .../ApolloMetadataClientMockedProvider.tsx | 2 +- .../hooks/useApolloMetadataClient.ts | 5 +- ...=> mapFieldMetadataToGraphQLQuery.test.ts} | 0 ...> mapObjectMetadataToGraphQLQuery.test.ts} | 0 .../object-record/hooks/useRecordChipData.ts | 2 +- .../ObjectFilterDropdownDateInput.tsx | 6 +- ...Label.test.tsx => getOperandLabel.test.ts} | 0 ...t.tsx => getOperandsForFilterType.test.ts} | 0 .../utils/getRelativeDateDisplayValue.ts | 2 +- ....test.tsx => turnSortsIntoOrderBy.test.ts} | 0 .../record-board/components/RecordBoard.tsx | 2 +- ...st.ts => getDraggedRecordPosition.test.ts} | 2 +- ...on.util.ts => getDraggedRecordPosition.ts} | 0 .../FieldContextProvider.tsx | 0 .../meta-types/hooks/useChipFieldDisplay.ts | 2 +- .../hooks/useRelationFromManyFieldDisplay.ts | 4 +- .../hooks/useRelationToOneFieldDisplay.ts | 4 +- .../__stories__/AddressFieldInput.stories.tsx | 4 +- .../__stories__/BooleanFieldInput.stories.tsx | 4 +- .../DateTimeFieldInput.stories.tsx | 4 +- .../__stories__/NumberFieldInput.stories.tsx | 4 +- .../__stories__/RatingFieldInput.stories.tsx | 4 +- .../RelationManyFieldInput.stories.tsx | 4 +- .../RelationToOneFieldInput.stories.tsx | 2 +- .../__stories__/TextFieldInput.stories.tsx | 4 +- ...ldButtonIcon.tsx => getFieldButtonIcon.ts} | 0 ...turnObjectDropdownFilterIntoQueryFilter.ts | 2 +- .../components/RecordIndexPageHeader.tsx | 6 +- .../components/RecordShowContainer.tsx | 2 +- ...dTableFetchedAllRecordsComponentStateV2.ts | 2 +- ...isRecordTableScrolledLeftComponentState.ts | 2 +- ...jectRecordsSpreasheetImportDialog.test.ts} | 3 +- .../hooks/useBuildAvailableFieldsForImport.ts | 2 +- ...OpenObjectRecordsSpreasheetImportDialog.ts | 2 +- .../buildRecordFromImportedStructuredRow.ts | 0 ...etSpreadSheetFieldValidationDefinitions.ts | 0 ...olumnDefinitionsFromObjectMetadata.test.ts | 27 +++++ .../utils/getRecordChipGenerators.ts | 2 +- .../opportunities/{ => types}/Opportunity.ts | 0 .../prefetch/constants/PrefetchConfig.ts | 4 +- ...ndAllFavoritesOperationSignatureFactory.ts | 0 .../findAllViewsOperationSignatureFactory.ts | 0 .../components/SettingsSkeletonLoader.tsx | 4 +- .../SettingsDataModelFieldPreviewCard.tsx | 2 +- .../components/SettingsDataModelOverview.tsx | 10 +- .../SettingsDataModelOverviewObject.tsx | 2 +- .../__tests__/calculateHandlePosition.test.ts | 0 .../calculateHandlePosition.ts | 0 .../components/SettingsObjectItemTableRow.tsx | 2 +- .../components/SettingsObjectSummaryCard.tsx | 2 +- .../SettingsDataModelObjectSummary.tsx | 2 +- .../SettingsDataModelObjectTypeTag.tsx | 0 .../SettingsObjectCoverImage.tsx | 4 +- .../SettingsObjectInactiveMenuDropDown.tsx | 0 ...ingsObjectInactiveMenuDropDown.stories.tsx | 0 ...ettingsDataModelObjectSettingsFormCard.tsx | 2 +- .../components/SettingsApiKeysTable.tsx | 2 +- ...st.ts => computeNewExpirationDate.test.ts} | 2 +- ...ation.test.ts => formatExpiration.test.ts} | 2 +- ...on-date.ts => computeNewExpirationDate.ts} | 0 ...rmat-expiration.ts => formatExpiration.ts} | 0 ...tion.tsx => useExpandedHeightAnimation.ts} | 0 .../components/SignInBackgroundMockPage.tsx | 10 +- .../{tests => __mocks__}/mockRsiValues.ts | 0 .../__stories__/MatchColumns.stories.tsx | 2 +- .../__stories__/SelectHeader.stories.tsx | 8 +- .../__stories__/SelectSheet.stories.tsx | 2 +- .../components/__stories__/Upload.stories.tsx | 2 +- .../__stories__/Validation.stories.tsx | 8 +- .../code-editor/components/CodeEditor.tsx | 12 +- .../codeEditorTheme.ts} | 0 .../date/components/InternalDatePicker.tsx | 2 +- .../components/RelativeDatePickerHeader.tsx | 9 +- .../RelativeDateDirectionSelectOptions.ts | 2 +- .../RelativeDateUnitSelectOptions.ts | 2 +- .../input/editor/components/BlockEditor.tsx | 6 +- .../editor/components/CustomAddBlockItem.tsx | 4 +- .../editor/components/CustomSideMenu.tsx | 4 +- ...=> getFirstNonEmptyLineOfRichText.test.ts} | 0 .../__stories__/DraggableItem.stories.tsx | 3 +- .../__stories__/DraggableList.stories.tsx | 5 +- .../page/{ => components}/BlankLayout.tsx | 0 .../page/{ => components}/DefaultLayout.tsx | 0 .../page/{ => components}/PageAddButton.tsx | 0 .../layout/page/{ => components}/PageBody.tsx | 0 .../page/{ => components}/PageContainer.tsx | 0 .../{ => components}/PageFavoriteButton.tsx | 0 .../page/{ => components}/PageHeader.tsx | 0 .../{ => components}/PageHotkeysEffect.tsx | 0 .../page/{ => components}/PagePanel.tsx | 0 .../{ => components}/RightDrawerContainer.tsx | 0 .../{ => components}/ShowPageContainer.tsx | 0 .../SubMenuTopBarContainer.tsx | 0 .../components/ShowPageSubContainer.tsx | 2 +- .../top-bar/{ => components}/TopBar.tsx | 0 .../page-title/{ => components}/PageTitle.tsx | 0 .../__tests__/useAvailableScopeId.test.tsx | 2 +- .../utils/createScopeInternalContext.ts | 3 +- ...isMobile.test.tsx => useIsMobile.test.tsx} | 0 ...lpha.ts => createComponentStateV2Alpha.ts} | 0 .../src/modules/views/components/ViewBar.tsx | 2 +- .../views/components/ViewBarPageTitle.tsx | 2 +- .../internal/usePersistViewFieldRecords.ts | 2 +- .../computeVariableDateViewFilterValue.ts | 2 +- .../utils}/resolveDateViewFilterValue.ts | 0 .../utils}/resolveFilterValue.ts | 2 +- .../utils}/resolveNumberViewFilterValue.ts | 0 ...sion.tsx => useActivateWorkflowVersion.ts} | 0 ...ion.tsx => useCreateNewWorkflowVersion.ts} | 0 .../{useCreateStep.tsx => useCreateStep.ts} | 0 ...on.tsx => useDeactivateWorkflowVersion.ts} | 0 ...eDeleteOneStep.tsx => useDeleteOneStep.ts} | 0 ...ion.tsx => useDeleteOneWorkflowVersion.ts} | 0 ...deCreation.tsx => useStartNodeCreation.ts} | 0 ...lection.tsx => useTriggerNodeSelection.ts} | 0 ...ep.tsx => useUpdateWorkflowVersionStep.ts} | 0 ...tsx => useUpdateWorkflowVersionTrigger.ts} | 0 ...kflowVersion.tsx => useWorkflowVersion.ts} | 0 ...n.tsx => useWorkflowWithCurrentVersion.ts} | 0 ...ertWorkflowWithCurrentVersionIsDefined.ts} | 0 .../fragments/workspaceMemberQueryFragment.ts | 0 .../mutations/addUserToWorkspace.ts | 0 .../addUserToWorkspaceByInviteToken.ts | 0 .../src/pages/not-found/NotFound.tsx | 2 +- .../pages/object-record/RecordIndexPage.tsx | 6 +- .../pages/object-record/RecordShowPage.tsx | 8 +- .../RecordShowPageBaseHeader.tsx | 2 +- .../object-record/RecordShowPageHeader.tsx | 2 +- .../src/pages/settings/Releases.tsx | 2 +- .../src/pages/settings/SettingsBilling.tsx | 2 +- .../src/pages/settings/SettingsProfile.tsx | 2 +- .../src/pages/settings/SettingsWorkspace.tsx | 2 +- .../settings/SettingsWorkspaceMembers.tsx | 2 +- .../settings/accounts/SettingsAccounts.tsx | 2 +- .../accounts/SettingsAccountsCalendars.tsx | 2 +- .../accounts/SettingsAccountsEmails.tsx | 2 +- .../settings/accounts/SettingsNewAccount.tsx | 2 +- .../crm-migration/SettingsCRMMigration.tsx | 2 +- .../settings/data-model/SettingsNewObject.tsx | 2 +- .../SettingsObjectDetailPageContent.tsx | 2 +- .../data-model/SettingsObjectEdit.tsx | 2 +- .../data-model/SettingsObjectFieldEdit.tsx | 2 +- .../SettingsObjectNewFieldConfigure.tsx | 2 +- .../SettingsObjectNewFieldSelect.tsx | 2 +- .../data-model/SettingsObjectOverview.tsx | 2 +- .../settings/data-model/SettingsObjects.tsx | 6 +- .../developers/SettingsDevelopers.tsx | 2 +- .../SettingsDevelopersApiKeyDetail.tsx | 6 +- .../api-keys/SettingsDevelopersApiKeysNew.tsx | 2 +- .../SettingsDevelopersWebhookDetail.tsx | 2 +- .../SettingsDevelopersWebhooksNew.tsx | 2 +- .../SettingsIntegrationDatabase.tsx | 2 +- ...tingsIntegrationEditDatabaseConnection.tsx | 2 +- ...ttingsIntegrationNewDatabaseConnection.tsx | 2 +- ...tingsIntegrationShowDatabaseConnection.tsx | 2 +- .../integrations/SettingsIntegrations.tsx | 2 +- .../components/SettingsAppearance.tsx | 2 +- .../SettingsServerlessFunctionDetail.tsx | 4 +- .../SettingsServerlessFunctions.tsx | 2 +- .../SettingsServerlessFunctionsNew.tsx | 2 +- .../decorators/ChipGeneratorsDecorator.tsx | 2 +- .../src/testing/decorators/PageDecorator.tsx | 2 +- .../testing/mock-data/timeline-activities.ts | 2 +- packages/twenty-front/vite.config.ts | 2 +- yarn.lock | 104 ++++++++++++++++++ 260 files changed, 500 insertions(+), 290 deletions(-) create mode 100644 packages/twenty-front/folderStructure.json rename packages/twenty-front/src/modules/activities/blocks/{ => components}/FileBlock.tsx (94%) rename packages/twenty-front/src/modules/activities/blocks/{schema.ts => constants/Schema.ts} (57%) rename packages/twenty-front/src/modules/activities/blocks/{slashMenu.tsx => utils/getSlashMenu.ts} (90%) rename packages/twenty-front/src/modules/activities/calendar/{ => graphql}/queries/fragments/timelineCalendarEventFragment.ts (84%) rename packages/twenty-front/src/modules/activities/calendar/{ => graphql}/queries/fragments/timelineCalendarEventParticipantFragment.ts (100%) rename packages/twenty-front/src/modules/activities/calendar/{ => graphql}/queries/fragments/timelineCalendarEventWithTotalFragment.ts (86%) rename packages/twenty-front/src/modules/activities/calendar/{ => graphql}/queries/getTimelineCalendarEventsFromCompanyId.ts (86%) rename packages/twenty-front/src/modules/activities/calendar/{ => graphql}/queries/getTimelineCalendarEventsFromPersonId.ts (86%) rename packages/twenty-front/src/modules/activities/emails/{ => graphql}/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts (100%) rename packages/twenty-front/src/modules/activities/emails/{ => graphql}/queries/__tests__/getTimelineThreadsFromPersonId.test.ts (100%) rename packages/twenty-front/src/modules/activities/emails/{ => graphql}/queries/fragments/participantFragment.ts (100%) rename packages/twenty-front/src/modules/activities/emails/{ => graphql}/queries/fragments/timelineThreadFragment.ts (80%) rename packages/twenty-front/src/modules/activities/emails/{ => graphql}/queries/fragments/timelineThreadWithTotalFragment.ts (71%) rename packages/twenty-front/src/modules/activities/emails/{ => graphql}/queries/getTimelineThreadsFromCompanyId.ts (88%) rename packages/twenty-front/src/modules/activities/emails/{ => graphql}/queries/getTimelineThreadsFromPersonId.ts (87%) rename packages/twenty-front/src/modules/activities/tasks/{ => components}/__stories__/TaskGroups.stories.tsx (100%) rename packages/twenty-front/src/modules/activities/tasks/{ => components}/__stories__/TaskList.stories.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/components/EventList.tsx (86%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/components/EventRow.tsx (89%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/components/EventsGroup.tsx (92%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/components/TimelineActivities.tsx (91%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/components/TimelineCreateButtonGroup.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities/components}/__stories__/TimelineActivities.stories.tsx (89%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/constants/FindManyTimelineActivitiesOrderBy.ts (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/contexts/TimelineActivityContext.ts (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/hooks/__tests__/useTimelineActivities.test.tsx (95%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/hooks/useLinkedObjectObjectMetadataItem.ts (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/hooks/useLinkedObjectsTitle.ts (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/hooks/useTimelineActivities.ts (90%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/activity/components/EventRowActivity.tsx (96%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/calendar/components/EventCardCalendarEvent.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/calendar/components/EventRowCalendarEvent.tsx (77%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/calendar/components/__stories__/EventCardCalendarEvent.stories.tsx (90%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/components/EventCard.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/components/EventCardToggleButton.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/components/EventIconDynamicComponent.tsx (88%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/components/EventRowDynamicComponent.tsx (84%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/main-object/components/EventFieldDiff.tsx (88%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/main-object/components/EventFieldDiffContainer.tsx (91%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/main-object/components/EventFieldDiffLabel.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/main-object/components/EventFieldDiffValue.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/main-object/components/EventFieldDiffValueEffect.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/main-object/components/EventRowMainObject.tsx (91%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/main-object/components/EventRowMainObjectUpdated.tsx (84%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx (90%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/message/components/EventCardMessage.tsx (98%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/message/components/EventCardMessageNotShared.tsx (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/message/components/EventRowMessage.tsx (79%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/rows/message/components/__stories__/EventCardMessage.stories.tsx (87%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/states/objectShowPageTargetableObjectIdState.ts (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/types/TimelineActivity.ts (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/types/TimelineActivityLinkedObject.ts (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/utils/__tests__/filterOutInvalidTimelineActivities.test.ts (96%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/utils/__tests__/getTimelineActivityAuthorFullName.test.ts (91%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/utils/__tests__/groupEventsByMonth.test.ts (100%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/utils/filterOutInvalidTimelineActivities.ts (95%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/utils/filterTimelineActivityByLinkedObjectTypes.ts (75%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/utils/getTimelineActivityAuthorFullName.ts (84%) rename packages/twenty-front/src/modules/activities/{timelineActivities => timeline-activities}/utils/groupEventsByMonth.ts (89%) rename packages/twenty-front/src/modules/apollo/utils/__tests__/{format-title.test.ts => formatTitle.test.ts} (91%) delete mode 100644 packages/twenty-front/src/modules/apollo/utils/__tests__/utils.test.ts rename packages/twenty-front/src/modules/apollo/utils/{format-title.ts => formatTitle.ts} (100%) rename packages/twenty-front/src/modules/apollo/utils/{index.ts => loggerLink.ts} (98%) rename packages/twenty-front/src/modules/app/{utils/createAppRouter.tsx => hooks/useCreateAppRouter.tsx} (95%) rename packages/twenty-front/src/modules/auth/hooks/{__test__ => __tests__}/useAuth.test.tsx (100%) rename packages/twenty-front/src/modules/auth/hooks/{__test__ => __tests__}/useIsLogged.test.ts (100%) rename packages/twenty-front/src/modules/auth/utils/{__test__ => __tests__}/passwordRegex.test.ts (100%) rename packages/twenty-front/src/modules/command-menu/hooks/{__test__ => __tests__}/useCommandMenu.test.tsx (100%) rename packages/twenty-front/src/modules/favorites/utils/{sort-favorites.util.ts => sortFavorites.ts} (100%) rename packages/twenty-front/src/modules/object-metadata/{context => contexts}/ApolloClientMetadataContext.ts (100%) rename packages/twenty-front/src/modules/object-metadata/{context => contexts}/PreComputedChipGeneratorsContext.ts (100%) rename packages/twenty-front/src/modules/object-metadata/utils/__tests__/{mapFieldMetadataToGraphQLQuery.test.tsx => mapFieldMetadataToGraphQLQuery.test.ts} (100%) rename packages/twenty-front/src/modules/object-metadata/utils/__tests__/{mapObjectMetadataToGraphQLQuery.test.tsx => mapObjectMetadataToGraphQLQuery.test.ts} (100%) rename packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/{getOperandLabel.test.tsx => getOperandLabel.test.ts} (100%) rename packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/{getOperandsForFilterType.test.tsx => getOperandsForFilterType.test.ts} (100%) rename packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/{turnSortsIntoOrderBy.test.tsx => turnSortsIntoOrderBy.test.ts} (100%) rename packages/twenty-front/src/modules/object-record/record-board/utils/__tests__/{get-dragged-record-position.util.test.ts => getDraggedRecordPosition.test.ts} (92%) rename packages/twenty-front/src/modules/object-record/record-board/utils/{get-dragged-record-position.util.ts => getDraggedRecordPosition.ts} (100%) rename packages/twenty-front/src/modules/object-record/record-field/meta-types/{__stories__ => components}/FieldContextProvider.tsx (100%) rename packages/twenty-front/src/modules/object-record/record-field/utils/{getFieldButtonIcon.tsx => getFieldButtonIcon.ts} (100%) rename packages/twenty-front/src/modules/object-record/spreadsheet-import/{__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.tsx => hooks/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.ts} (98%) rename packages/twenty-front/src/modules/object-record/spreadsheet-import/{util => utils}/buildRecordFromImportedStructuredRow.ts (100%) rename packages/twenty-front/src/modules/object-record/spreadsheet-import/{util => utils}/getSpreadSheetFieldValidationDefinitions.ts (100%) create mode 100644 packages/twenty-front/src/modules/object-record/utils/__tests__/computeRecordBoardColumnDefinitionsFromObjectMetadata.test.ts rename packages/twenty-front/src/modules/opportunities/{ => types}/Opportunity.ts (100%) rename packages/twenty-front/src/modules/prefetch/{ => graphql}/operation-signatures/factories/findAllFavoritesOperationSignatureFactory.ts (100%) rename packages/twenty-front/src/modules/prefetch/{ => graphql}/operation-signatures/factories/findAllViewsOperationSignatureFactory.ts (100%) rename packages/twenty-front/src/modules/settings/data-model/graph-overview/{util => utils}/__tests__/calculateHandlePosition.test.ts (100%) rename packages/twenty-front/src/modules/settings/data-model/graph-overview/{util => utils}/calculateHandlePosition.ts (100%) rename packages/twenty-front/src/modules/settings/data-model/objects/{ => components}/SettingsDataModelObjectSummary.tsx (96%) rename packages/twenty-front/src/modules/settings/data-model/objects/{ => components}/SettingsDataModelObjectTypeTag.tsx (100%) rename packages/twenty-front/src/modules/settings/data-model/objects/{ => components}/SettingsObjectCoverImage.tsx (91%) rename packages/twenty-front/src/modules/settings/data-model/objects/{ => components}/SettingsObjectInactiveMenuDropDown.tsx (100%) rename packages/twenty-front/src/modules/settings/data-model/objects/{ => components}/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx (100%) rename packages/twenty-front/src/modules/settings/developers/utils/__tests__/{compute-new-expiration-date.test.ts => computeNewExpirationDate.test.ts} (96%) rename packages/twenty-front/src/modules/settings/developers/utils/__tests__/{format-expiration.test.ts => formatExpiration.test.ts} (99%) rename packages/twenty-front/src/modules/settings/developers/utils/{compute-new-expiration-date.ts => computeNewExpirationDate.ts} (100%) rename packages/twenty-front/src/modules/settings/developers/utils/{format-expiration.ts => formatExpiration.ts} (100%) rename packages/twenty-front/src/modules/settings/hooks/{useExpandedHeightAnimation.tsx => useExpandedHeightAnimation.ts} (100%) rename packages/twenty-front/src/modules/spreadsheet-import/{tests => __mocks__}/mockRsiValues.ts (100%) rename packages/twenty-front/src/modules/ui/input/code-editor/{theme/CodeEditorTheme.ts => utils/codeEditorTheme.ts} (100%) rename packages/twenty-front/src/modules/ui/input/editor/utils/__tests__/{getFirstNonEmptyLineOfRichText.test.tsx => getFirstNonEmptyLineOfRichText.test.ts} (100%) rename packages/twenty-front/src/modules/ui/layout/draggable-list/{ => components}/__stories__/DraggableItem.stories.tsx (92%) rename packages/twenty-front/src/modules/ui/layout/draggable-list/{ => components}/__stories__/DraggableList.stories.tsx (89%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/BlankLayout.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/DefaultLayout.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/PageAddButton.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/PageBody.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/PageContainer.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/PageFavoriteButton.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/PageHeader.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/PageHotkeysEffect.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/PagePanel.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/RightDrawerContainer.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/ShowPageContainer.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/page/{ => components}/SubMenuTopBarContainer.tsx (100%) rename packages/twenty-front/src/modules/ui/layout/top-bar/{ => components}/TopBar.tsx (100%) rename packages/twenty-front/src/modules/ui/utilities/page-title/{ => components}/PageTitle.tsx (100%) rename packages/twenty-front/src/modules/ui/utilities/responsive/hooks/__tests__/{isMobile.test.tsx => useIsMobile.test.tsx} (100%) rename packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/{createComponentStateV2_alpha.ts => createComponentStateV2Alpha.ts} (100%) rename packages/twenty-front/src/modules/views/{utils/view-filter-value => view-filter-value/utils}/computeVariableDateViewFilterValue.ts (83%) rename packages/twenty-front/src/modules/views/{utils/view-filter-value => view-filter-value/utils}/resolveDateViewFilterValue.ts (100%) rename packages/twenty-front/src/modules/views/{utils/view-filter-value => view-filter-value/utils}/resolveFilterValue.ts (91%) rename packages/twenty-front/src/modules/views/{utils/view-filter-value => view-filter-value/utils}/resolveNumberViewFilterValue.ts (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useActivateWorkflowVersion.tsx => useActivateWorkflowVersion.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useCreateNewWorkflowVersion.tsx => useCreateNewWorkflowVersion.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useCreateStep.tsx => useCreateStep.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useDeactivateWorkflowVersion.tsx => useDeactivateWorkflowVersion.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useDeleteOneStep.tsx => useDeleteOneStep.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useDeleteOneWorkflowVersion.tsx => useDeleteOneWorkflowVersion.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useStartNodeCreation.tsx => useStartNodeCreation.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useTriggerNodeSelection.tsx => useTriggerNodeSelection.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useUpdateWorkflowVersionStep.tsx => useUpdateWorkflowVersionStep.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useUpdateWorkflowVersionTrigger.tsx => useUpdateWorkflowVersionTrigger.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useWorkflowVersion.tsx => useWorkflowVersion.ts} (100%) rename packages/twenty-front/src/modules/workflow/hooks/{useWorkflowWithCurrentVersion.tsx => useWorkflowWithCurrentVersion.ts} (100%) rename packages/twenty-front/src/modules/workflow/utils/{assertWorkflowWithCurrentVersionIsDefined.tsx => assertWorkflowWithCurrentVersionIsDefined.ts} (100%) rename packages/twenty-front/src/modules/workspace-member/{grapqhql => graphql}/fragments/workspaceMemberQueryFragment.ts (100%) rename packages/twenty-front/src/modules/workspace-member/{grapqhql => graphql}/mutations/addUserToWorkspace.ts (100%) rename packages/twenty-front/src/modules/workspace-member/{grapqhql => graphql}/mutations/addUserToWorkspaceByInviteToken.ts (100%) diff --git a/.gitignore b/.gitignore index c5bb33e003d1..0d87dfc1cdc6 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ .nx/installation .nx/cache +projectStructure.cache.json .pnp.* .yarn/* diff --git a/nx.json b/nx.json index 35b6e7501700..0030428ee966 100644 --- a/nx.json +++ b/nx.json @@ -113,7 +113,7 @@ "outputs": ["{projectRoot}/{options.output-dir}"], "options": { "cwd": "{projectRoot}", - "command": "storybook build", + "command": "VITE_DISABLE_ESLINT_CHECKER=true storybook build", "output-dir": "storybook-static", "config-dir": ".storybook" } diff --git a/package.json b/package.json index f86d4c1b9d08..a83f2180fa98 100644 --- a/package.json +++ b/package.json @@ -294,6 +294,7 @@ "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prettier": "^5.1.2", + "eslint-plugin-project-structure": "^3.7.2", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", diff --git a/packages/twenty-front/.eslintrc.cjs b/packages/twenty-front/.eslintrc.cjs index df4daf7633a4..790724178919 100644 --- a/packages/twenty-front/.eslintrc.cjs +++ b/packages/twenty-front/.eslintrc.cjs @@ -21,7 +21,14 @@ module.exports = { parserOptions: { project: ['packages/twenty-front/tsconfig.{json,*.json}'], }, - rules: {}, + plugins: ['project-structure'], + settings: { + 'project-structure/folder-structure-config-path': + 'packages/twenty-front/folderStructure.json', + }, + rules: { + 'project-structure/folder-structure': 'error', + }, }, ], }; diff --git a/packages/twenty-front/folderStructure.json b/packages/twenty-front/folderStructure.json new file mode 100644 index 000000000000..4dab3b2cda49 --- /dev/null +++ b/packages/twenty-front/folderStructure.json @@ -0,0 +1,81 @@ +{ + "$schema": "../../node_modules/eslint-plugin-project-structure/folderStructure.schema.json", + "regexParameters": { + "camelCase": "^[a-z]+([A-Za-z0-9]+)+" + }, + "structure": [ + { + "name": "packages", + "children": [ + { + "name": "twenty-front", + "children": [ + { "name": "*", "children": [] }, + { "name": "*" }, + { + "name": "src", + "children": [ + { "name": "*", "children": [] }, + { "name": "*" }, + { + "name": "modules", + "children": [ + { "ruleId": "moduleFolderRule" }, + { "name": "types", "ruleId": "doNotCheckLeafFolderRule" } + ] + } + ] + } + ] + } + ] + } + ], + "rules": { + "moduleFolderRule": { + "name": "^(?!utils$|hooks$|states$|types$|graphql$|components$|effect-components$|constants$|validation-schemas$|contexts$|scopes$|services$|errors$)[a-z][a-z0-9]**(?:-[a-z0-9]+)**$", + "folderRecursionLimit": 6, + "children": [ + { "ruleId": "moduleFolderRule" }, + { "name": "hooks", "ruleId": "hooksLeafFolderRule" }, + { "name": "utils", "ruleId": "utilsLeafFolderRule" }, + { "name": "states", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "types", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "graphql", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "components", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "effect-components", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "constants", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "validation-schemas", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "contexts", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "scopes", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "services", "ruleId": "doNotCheckLeafFolderRule" }, + { "name": "errors", "ruleId": "doNotCheckLeafFolderRule" } + ] + }, + "hooksLeafFolderRule": { + "folderRecursionLimit": 2, + "children": [ + { "name": "use{PascalCase}.(ts|tsx)" }, + { + "name": "__tests__", + "children": [{ "name": "use{PascalCase}.test.(ts|tsx)" }] + }, + { "name": "internal", "ruleId": "hooksLeafFolderRule" } + ] + }, + "doNotCheckLeafFolderRule": { + "folderRecursionLimit": 1, + "children": [{ "name": "*" }, { "name": "*", "children": [] }] + }, + "utilsLeafFolderRule": { + "folderRecursionLimit": 1, + "children": [ + { "name": "{camelCase}.ts" }, + { + "name": "__tests__", + "children": [{ "name": "{camelCase}.test.ts" }] + } + ] + } + } +} diff --git a/packages/twenty-front/jest.config.ts b/packages/twenty-front/jest.config.ts index 8ed7f398db4e..c3e8ab4148e7 100644 --- a/packages/twenty-front/jest.config.ts +++ b/packages/twenty-front/jest.config.ts @@ -25,9 +25,9 @@ const jestConfig: JestConfigWithTsJest = { extensionsToTreatAsEsm: ['.ts', '.tsx'], coverageThreshold: { global: { - statements: 60, + statements: 59, lines: 55, - functions: 50, + functions: 49, }, }, collectCoverageFrom: ['/src/**/*.ts'], diff --git a/packages/twenty-front/project.json b/packages/twenty-front/project.json index 3ed94b22f256..245fde1fac34 100644 --- a/packages/twenty-front/project.json +++ b/packages/twenty-front/project.json @@ -52,7 +52,9 @@ "reportUnusedDisableDirectives": "error" }, "configurations": { - "ci": { "eslintConfig": "{projectRoot}/.eslintrc-ci.cjs" }, + "ci": { + "eslintConfig": "{projectRoot}/.eslintrc-ci.cjs" + }, "fix": {} } }, diff --git a/packages/twenty-front/src/modules/activities/blocks/FileBlock.tsx b/packages/twenty-front/src/modules/activities/blocks/components/FileBlock.tsx similarity index 94% rename from packages/twenty-front/src/modules/activities/blocks/FileBlock.tsx rename to packages/twenty-front/src/modules/activities/blocks/components/FileBlock.tsx index 680ac551f662..d1d308dcd4f2 100644 --- a/packages/twenty-front/src/modules/activities/blocks/FileBlock.tsx +++ b/packages/twenty-front/src/modules/activities/blocks/components/FileBlock.tsx @@ -8,9 +8,9 @@ import { AppThemeProvider } from '@/ui/theme/components/AppThemeProvider'; import { isDefined } from '~/utils/isDefined'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; -import { AttachmentIcon } from '../files/components/AttachmentIcon'; -import { AttachmentType } from '../files/types/Attachment'; -import { getFileType } from '../files/utils/getFileType'; +import { AttachmentIcon } from '../../files/components/AttachmentIcon'; +import { AttachmentType } from '../../files/types/Attachment'; +import { getFileType } from '../../files/utils/getFileType'; const StyledFileInput = styled.input` display: none; diff --git a/packages/twenty-front/src/modules/activities/blocks/schema.ts b/packages/twenty-front/src/modules/activities/blocks/constants/Schema.ts similarity index 57% rename from packages/twenty-front/src/modules/activities/blocks/schema.ts rename to packages/twenty-front/src/modules/activities/blocks/constants/Schema.ts index d6ea82eac19b..2584f3c7b8c5 100644 --- a/packages/twenty-front/src/modules/activities/blocks/schema.ts +++ b/packages/twenty-front/src/modules/activities/blocks/constants/Schema.ts @@ -1,8 +1,8 @@ import { BlockNoteSchema, defaultBlockSpecs } from '@blocknote/core'; -import { FileBlock } from './FileBlock'; +import { FileBlock } from '../components/FileBlock'; -export const blockSchema = BlockNoteSchema.create({ +export const BLOCK_SCHEMA = BlockNoteSchema.create({ blockSpecs: { ...defaultBlockSpecs, file: FileBlock, diff --git a/packages/twenty-front/src/modules/activities/blocks/slashMenu.tsx b/packages/twenty-front/src/modules/activities/blocks/utils/getSlashMenu.ts similarity index 90% rename from packages/twenty-front/src/modules/activities/blocks/slashMenu.tsx rename to packages/twenty-front/src/modules/activities/blocks/utils/getSlashMenu.ts index 34a161bab747..760a778b57b2 100644 --- a/packages/twenty-front/src/modules/activities/blocks/slashMenu.tsx +++ b/packages/twenty-front/src/modules/activities/blocks/utils/getSlashMenu.ts @@ -18,7 +18,7 @@ import { import { SuggestionItem } from '@/ui/input/editor/components/CustomSlashMenu'; -import { blockSchema } from './schema'; +import { BLOCK_SCHEMA } from '../constants/Schema'; const Icons: Record = { 'Heading 1': IconH1, @@ -35,7 +35,7 @@ const Icons: Record = { Emoji: IconMoodSmile, }; -export const getSlashMenu = (editor: typeof blockSchema.BlockNoteEditor) => { +export const getSlashMenu = (editor: typeof BLOCK_SCHEMA.BlockNoteEditor) => { const items: SuggestionItem[] = [ ...getDefaultReactSlashMenuItems(editor).map((x) => ({ ...x, diff --git a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx index 360eccbbcc2a..83f06303b74f 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx @@ -5,9 +5,9 @@ import { H3Title } from 'twenty-ui'; import { CalendarMonthCard } from '@/activities/calendar/components/CalendarMonthCard'; import { TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE } from '@/activities/calendar/constants/Calendar'; import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext'; +import { getTimelineCalendarEventsFromCompanyId } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromCompanyId'; +import { getTimelineCalendarEventsFromPersonId } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromPersonId'; import { useCalendarEvents } from '@/activities/calendar/hooks/useCalendarEvents'; -import { getTimelineCalendarEventsFromCompanyId } from '@/activities/calendar/queries/getTimelineCalendarEventsFromCompanyId'; -import { getTimelineCalendarEventsFromPersonId } from '@/activities/calendar/queries/getTimelineCalendarEventsFromPersonId'; import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader'; import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { useCustomResolver } from '@/activities/hooks/useCustomResolver'; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/__stories__/Calendar.stories.tsx b/packages/twenty-front/src/modules/activities/calendar/components/__stories__/Calendar.stories.tsx index b2732df86544..eb4aa38eda72 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/__stories__/Calendar.stories.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/__stories__/Calendar.stories.tsx @@ -1,10 +1,10 @@ import { getOperationName } from '@apollo/client/utilities'; import { Meta, StoryObj } from '@storybook/react'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { ComponentDecorator } from 'twenty-ui'; import { Calendar } from '@/activities/calendar/components/Calendar'; -import { getTimelineCalendarEventsFromCompanyId } from '@/activities/calendar/queries/getTimelineCalendarEventsFromCompanyId'; +import { getTimelineCalendarEventsFromCompanyId } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromCompanyId'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; diff --git a/packages/twenty-front/src/modules/activities/calendar/queries/fragments/timelineCalendarEventFragment.ts b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventFragment.ts similarity index 84% rename from packages/twenty-front/src/modules/activities/calendar/queries/fragments/timelineCalendarEventFragment.ts rename to packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventFragment.ts index d98c7bcf81b2..eb152294ccea 100644 --- a/packages/twenty-front/src/modules/activities/calendar/queries/fragments/timelineCalendarEventFragment.ts +++ b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventFragment.ts @@ -1,7 +1,6 @@ +import { timelineCalendarEventParticipantFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventParticipantFragment'; import { gql } from '@apollo/client'; -import { timelineCalendarEventParticipantFragment } from '@/activities/calendar/queries/fragments/timelineCalendarEventParticipantFragment'; - export const timelineCalendarEventFragment = gql` fragment TimelineCalendarEventFragment on TimelineCalendarEvent { id diff --git a/packages/twenty-front/src/modules/activities/calendar/queries/fragments/timelineCalendarEventParticipantFragment.ts b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventParticipantFragment.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/calendar/queries/fragments/timelineCalendarEventParticipantFragment.ts rename to packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventParticipantFragment.ts diff --git a/packages/twenty-front/src/modules/activities/calendar/queries/fragments/timelineCalendarEventWithTotalFragment.ts b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventWithTotalFragment.ts similarity index 86% rename from packages/twenty-front/src/modules/activities/calendar/queries/fragments/timelineCalendarEventWithTotalFragment.ts rename to packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventWithTotalFragment.ts index 2a76f0f7fa41..58de733417c1 100644 --- a/packages/twenty-front/src/modules/activities/calendar/queries/fragments/timelineCalendarEventWithTotalFragment.ts +++ b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventWithTotalFragment.ts @@ -1,7 +1,6 @@ +import { timelineCalendarEventFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventFragment'; import { gql } from '@apollo/client'; -import { timelineCalendarEventFragment } from '@/activities/calendar/queries/fragments/timelineCalendarEventFragment'; - export const timelineCalendarEventWithTotalFragment = gql` fragment TimelineCalendarEventsWithTotalFragment on TimelineCalendarEventsWithTotal { totalNumberOfCalendarEvents diff --git a/packages/twenty-front/src/modules/activities/calendar/queries/getTimelineCalendarEventsFromCompanyId.ts b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/getTimelineCalendarEventsFromCompanyId.ts similarity index 86% rename from packages/twenty-front/src/modules/activities/calendar/queries/getTimelineCalendarEventsFromCompanyId.ts rename to packages/twenty-front/src/modules/activities/calendar/graphql/queries/getTimelineCalendarEventsFromCompanyId.ts index e454e67452f3..c43d197e43ff 100644 --- a/packages/twenty-front/src/modules/activities/calendar/queries/getTimelineCalendarEventsFromCompanyId.ts +++ b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/getTimelineCalendarEventsFromCompanyId.ts @@ -1,7 +1,6 @@ +import { timelineCalendarEventWithTotalFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventWithTotalFragment'; import { gql } from '@apollo/client'; -import { timelineCalendarEventWithTotalFragment } from '@/activities/calendar/queries/fragments/timelineCalendarEventWithTotalFragment'; - export const getTimelineCalendarEventsFromCompanyId = gql` query GetTimelineCalendarEventsFromCompanyId( $companyId: UUID! diff --git a/packages/twenty-front/src/modules/activities/calendar/queries/getTimelineCalendarEventsFromPersonId.ts b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/getTimelineCalendarEventsFromPersonId.ts similarity index 86% rename from packages/twenty-front/src/modules/activities/calendar/queries/getTimelineCalendarEventsFromPersonId.ts rename to packages/twenty-front/src/modules/activities/calendar/graphql/queries/getTimelineCalendarEventsFromPersonId.ts index 7d9f221fbc78..3285fb475d23 100644 --- a/packages/twenty-front/src/modules/activities/calendar/queries/getTimelineCalendarEventsFromPersonId.ts +++ b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/getTimelineCalendarEventsFromPersonId.ts @@ -1,7 +1,6 @@ +import { timelineCalendarEventWithTotalFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventWithTotalFragment'; import { gql } from '@apollo/client'; -import { timelineCalendarEventWithTotalFragment } from '@/activities/calendar/queries/fragments/timelineCalendarEventWithTotalFragment'; - export const getTimelineCalendarEventsFromPersonId = gql` query GetTimelineCalendarEventsFromPersonId( $personId: UUID! diff --git a/packages/twenty-front/src/modules/activities/components/RichTextEditor.tsx b/packages/twenty-front/src/modules/activities/components/RichTextEditor.tsx index c6842395f64f..21ac7228d3da 100644 --- a/packages/twenty-front/src/modules/activities/components/RichTextEditor.tsx +++ b/packages/twenty-front/src/modules/activities/components/RichTextEditor.tsx @@ -7,7 +7,6 @@ import { Key } from 'ts-key-enum'; import { useDebouncedCallback } from 'use-debounce'; import { v4 } from 'uuid'; -import { blockSchema } from '@/activities/blocks/schema'; import { useUpsertActivity } from '@/activities/hooks/useUpsertActivity'; import { activityBodyFamilyState } from '@/activities/states/activityBodyFamilyState'; import { activityTitleHasBeenSetFamilyState } from '@/activities/states/activityTitleHasBeenSetFamilyState'; @@ -27,6 +26,7 @@ import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { getFileType } from '../files/utils/getFileType'; +import { BLOCK_SCHEMA } from '@/activities/blocks/constants/Schema'; import { Note } from '@/activities/types/Note'; import { Task } from '@/activities/types/Task'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; @@ -287,7 +287,7 @@ export const RichTextEditor = ({ const editor = useCreateBlockNote({ initialContent: initialBody, domAttributes: { editor: { class: 'editor' } }, - schema: blockSchema, + schema: BLOCK_SCHEMA, uploadFile: handleUploadAttachment, }); diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx index 8a3eef7ea33f..a46df19b7f1b 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx @@ -6,8 +6,8 @@ import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomRes import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { EmailThreadPreview } from '@/activities/emails/components/EmailThreadPreview'; import { TIMELINE_THREADS_DEFAULT_PAGE_SIZE } from '@/activities/emails/constants/Messaging'; -import { getTimelineThreadsFromCompanyId } from '@/activities/emails/queries/getTimelineThreadsFromCompanyId'; -import { getTimelineThreadsFromPersonId } from '@/activities/emails/queries/getTimelineThreadsFromPersonId'; +import { getTimelineThreadsFromCompanyId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromCompanyId'; +import { getTimelineThreadsFromPersonId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromPersonId'; import { useCustomResolver } from '@/activities/hooks/useCustomResolver'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; diff --git a/packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts b/packages/twenty-front/src/modules/activities/emails/graphql/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts rename to packages/twenty-front/src/modules/activities/emails/graphql/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts diff --git a/packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromPersonId.test.ts b/packages/twenty-front/src/modules/activities/emails/graphql/queries/__tests__/getTimelineThreadsFromPersonId.test.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromPersonId.test.ts rename to packages/twenty-front/src/modules/activities/emails/graphql/queries/__tests__/getTimelineThreadsFromPersonId.test.ts diff --git a/packages/twenty-front/src/modules/activities/emails/queries/fragments/participantFragment.ts b/packages/twenty-front/src/modules/activities/emails/graphql/queries/fragments/participantFragment.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/emails/queries/fragments/participantFragment.ts rename to packages/twenty-front/src/modules/activities/emails/graphql/queries/fragments/participantFragment.ts diff --git a/packages/twenty-front/src/modules/activities/emails/queries/fragments/timelineThreadFragment.ts b/packages/twenty-front/src/modules/activities/emails/graphql/queries/fragments/timelineThreadFragment.ts similarity index 80% rename from packages/twenty-front/src/modules/activities/emails/queries/fragments/timelineThreadFragment.ts rename to packages/twenty-front/src/modules/activities/emails/graphql/queries/fragments/timelineThreadFragment.ts index d5728f23efaf..7d8f8ab9c351 100644 --- a/packages/twenty-front/src/modules/activities/emails/queries/fragments/timelineThreadFragment.ts +++ b/packages/twenty-front/src/modules/activities/emails/graphql/queries/fragments/timelineThreadFragment.ts @@ -1,6 +1,6 @@ import { gql } from '@apollo/client'; -import { participantFragment } from '@/activities/emails/queries/fragments/participantFragment'; +import { participantFragment } from '@/activities/emails/graphql/queries/fragments/participantFragment'; export const timelineThreadFragment = gql` fragment TimelineThreadFragment on TimelineThread { diff --git a/packages/twenty-front/src/modules/activities/emails/queries/fragments/timelineThreadWithTotalFragment.ts b/packages/twenty-front/src/modules/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment.ts similarity index 71% rename from packages/twenty-front/src/modules/activities/emails/queries/fragments/timelineThreadWithTotalFragment.ts rename to packages/twenty-front/src/modules/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment.ts index 89dc76d19b11..b5a8f351dacb 100644 --- a/packages/twenty-front/src/modules/activities/emails/queries/fragments/timelineThreadWithTotalFragment.ts +++ b/packages/twenty-front/src/modules/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment.ts @@ -1,7 +1,6 @@ +import { timelineThreadFragment } from '@/activities/emails/graphql/queries/fragments/timelineThreadFragment'; import { gql } from '@apollo/client'; -import { timelineThreadFragment } from '@/activities/emails/queries/fragments/timelineThreadFragment'; - export const timelineThreadWithTotalFragment = gql` fragment TimelineThreadsWithTotalFragment on TimelineThreadsWithTotal { totalNumberOfThreads diff --git a/packages/twenty-front/src/modules/activities/emails/queries/getTimelineThreadsFromCompanyId.ts b/packages/twenty-front/src/modules/activities/emails/graphql/queries/getTimelineThreadsFromCompanyId.ts similarity index 88% rename from packages/twenty-front/src/modules/activities/emails/queries/getTimelineThreadsFromCompanyId.ts rename to packages/twenty-front/src/modules/activities/emails/graphql/queries/getTimelineThreadsFromCompanyId.ts index 589905550c7d..e999e676b94e 100644 --- a/packages/twenty-front/src/modules/activities/emails/queries/getTimelineThreadsFromCompanyId.ts +++ b/packages/twenty-front/src/modules/activities/emails/graphql/queries/getTimelineThreadsFromCompanyId.ts @@ -1,7 +1,6 @@ +import { timelineThreadWithTotalFragment } from '@/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment'; import { gql } from '@apollo/client'; -import { timelineThreadWithTotalFragment } from '@/activities/emails/queries/fragments/timelineThreadWithTotalFragment'; - export const getTimelineThreadsFromCompanyId = gql` query GetTimelineThreadsFromCompanyId( $companyId: UUID! diff --git a/packages/twenty-front/src/modules/activities/emails/queries/getTimelineThreadsFromPersonId.ts b/packages/twenty-front/src/modules/activities/emails/graphql/queries/getTimelineThreadsFromPersonId.ts similarity index 87% rename from packages/twenty-front/src/modules/activities/emails/queries/getTimelineThreadsFromPersonId.ts rename to packages/twenty-front/src/modules/activities/emails/graphql/queries/getTimelineThreadsFromPersonId.ts index 84cd7053791e..7f1877f112eb 100644 --- a/packages/twenty-front/src/modules/activities/emails/queries/getTimelineThreadsFromPersonId.ts +++ b/packages/twenty-front/src/modules/activities/emails/graphql/queries/getTimelineThreadsFromPersonId.ts @@ -1,6 +1,6 @@ import { gql } from '@apollo/client'; -import { timelineThreadWithTotalFragment } from '@/activities/emails/queries/fragments/timelineThreadWithTotalFragment'; +import { timelineThreadWithTotalFragment } from '@/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment'; export const getTimelineThreadsFromPersonId = gql` query GetTimelineThreadsFromPersonId( diff --git a/packages/twenty-front/src/modules/activities/hooks/useRefreshShowPageFindManyActivitiesQueries.ts b/packages/twenty-front/src/modules/activities/hooks/useRefreshShowPageFindManyActivitiesQueries.ts index e054014aa2be..e3295d57e991 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useRefreshShowPageFindManyActivitiesQueries.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useRefreshShowPageFindManyActivitiesQueries.ts @@ -1,7 +1,7 @@ import { useRecoilValue } from 'recoil'; import { usePrepareFindManyActivitiesQuery } from '@/activities/hooks/usePrepareFindManyActivitiesQuery'; -import { objectShowPageTargetableObjectState } from '@/activities/timelineActivities/states/objectShowPageTargetableObjectIdState'; +import { objectShowPageTargetableObjectState } from '@/activities/timeline-activities/states/objectShowPageTargetableObjectIdState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts b/packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts index 4c1c6e2499fc..76e91ec8bf53 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts @@ -4,7 +4,7 @@ import { useCreateActivityInDB } from '@/activities/hooks/useCreateActivityInDB' import { useRefreshShowPageFindManyActivitiesQueries } from '@/activities/hooks/useRefreshShowPageFindManyActivitiesQueries'; import { isActivityInCreateModeState } from '@/activities/states/isActivityInCreateModeState'; import { isUpsertingActivityInDBState } from '@/activities/states/isCreatingActivityInDBState'; -import { objectShowPageTargetableObjectState } from '@/activities/timelineActivities/states/objectShowPageTargetableObjectIdState'; +import { objectShowPageTargetableObjectState } from '@/activities/timeline-activities/states/objectShowPageTargetableObjectIdState'; import { Note } from '@/activities/types/Note'; import { Task } from '@/activities/types/Task'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; diff --git a/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts b/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts index 04aa231d4c84..1a8248543747 100644 --- a/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts +++ b/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts @@ -3,7 +3,7 @@ import { useRecoilState } from 'recoil'; import { useActivities } from '@/activities/hooks/useActivities'; import { currentNotesQueryVariablesState } from '@/activities/notes/states/currentNotesQueryVariablesState'; -import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timelineActivities/constants/FindManyTimelineActivitiesOrderBy'; +import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline-activities/constants/FindManyTimelineActivitiesOrderBy'; import { Note } from '@/activities/types/Note'; import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; diff --git a/packages/twenty-front/src/modules/activities/tasks/components/PageAddTaskButton.tsx b/packages/twenty-front/src/modules/activities/tasks/components/PageAddTaskButton.tsx index 265780072a7d..a7168d35ec85 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/PageAddTaskButton.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/PageAddTaskButton.tsx @@ -1,6 +1,6 @@ import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { PageAddButton } from '@/ui/layout/page/PageAddButton'; +import { PageAddButton } from '@/ui/layout/page/components/PageAddButton'; export const PageAddTaskButton = () => { const openCreateActivity = useOpenCreateActivityDrawer({ diff --git a/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskGroups.stories.tsx b/packages/twenty-front/src/modules/activities/tasks/components/__stories__/TaskGroups.stories.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/tasks/__stories__/TaskGroups.stories.tsx rename to packages/twenty-front/src/modules/activities/tasks/components/__stories__/TaskGroups.stories.tsx diff --git a/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskList.stories.tsx b/packages/twenty-front/src/modules/activities/tasks/components/__stories__/TaskList.stories.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/tasks/__stories__/TaskList.stories.tsx rename to packages/twenty-front/src/modules/activities/tasks/components/__stories__/TaskList.stories.tsx diff --git a/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts b/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts index ef210d328a25..2085284d130d 100644 --- a/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts +++ b/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts @@ -1,5 +1,5 @@ import { useActivities } from '@/activities/hooks/useActivities'; -import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timelineActivities/constants/FindManyTimelineActivitiesOrderBy'; +import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline-activities/constants/FindManyTimelineActivitiesOrderBy'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { Task } from '@/activities/types/Task'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventList.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx similarity index 86% rename from packages/twenty-front/src/modules/activities/timelineActivities/components/EventList.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx index bf82cc2a42da..86b053536d88 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventList.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx @@ -1,10 +1,10 @@ import styled from '@emotion/styled'; import { ReactElement } from 'react'; -import { EventsGroup } from '@/activities/timelineActivities/components/EventsGroup'; -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; -import { filterOutInvalidTimelineActivities } from '@/activities/timelineActivities/utils/filterOutInvalidTimelineActivities'; -import { groupEventsByMonth } from '@/activities/timelineActivities/utils/groupEventsByMonth'; +import { EventsGroup } from '@/activities/timeline-activities/components/EventsGroup'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; +import { filterOutInvalidTimelineActivities } from '@/activities/timeline-activities/utils/filterOutInvalidTimelineActivities'; +import { groupEventsByMonth } from '@/activities/timeline-activities/utils/groupEventsByMonth'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventRow.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx similarity index 89% rename from packages/twenty-front/src/modules/activities/timelineActivities/components/EventRow.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx index e046316132df..e2cd91889021 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventRow.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx @@ -2,13 +2,13 @@ import styled from '@emotion/styled'; import { useContext } from 'react'; import { useRecoilValue } from 'recoil'; -import { TimelineActivityContext } from '@/activities/timelineActivities/contexts/TimelineActivityContext'; +import { TimelineActivityContext } from '@/activities/timeline-activities/contexts/TimelineActivityContext'; -import { useLinkedObjectObjectMetadataItem } from '@/activities/timelineActivities/hooks/useLinkedObjectObjectMetadataItem'; -import { EventIconDynamicComponent } from '@/activities/timelineActivities/rows/components/EventIconDynamicComponent'; -import { EventRowDynamicComponent } from '@/activities/timelineActivities/rows/components/EventRowDynamicComponent'; -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; -import { getTimelineActivityAuthorFullName } from '@/activities/timelineActivities/utils/getTimelineActivityAuthorFullName'; +import { useLinkedObjectObjectMetadataItem } from '@/activities/timeline-activities/hooks/useLinkedObjectObjectMetadataItem'; +import { EventIconDynamicComponent } from '@/activities/timeline-activities/rows/components/EventIconDynamicComponent'; +import { EventRowDynamicComponent } from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; +import { getTimelineActivityAuthorFullName } from '@/activities/timeline-activities/utils/getTimelineActivityAuthorFullName'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventsGroup.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventsGroup.tsx similarity index 92% rename from packages/twenty-front/src/modules/activities/timelineActivities/components/EventsGroup.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/components/EventsGroup.tsx index fe368ae9bab9..590f5657c66c 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventsGroup.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventsGroup.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; -import { EventRow } from '@/activities/timelineActivities/components/EventRow'; -import { EventGroup } from '@/activities/timelineActivities/utils/groupEventsByMonth'; +import { EventRow } from '@/activities/timeline-activities/components/EventRow'; +import { EventGroup } from '@/activities/timeline-activities/utils/groupEventsByMonth'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; type EventsGroupProps = { diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineActivities.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineActivities.tsx similarity index 91% rename from packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineActivities.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineActivities.tsx index bbda464681f9..a938ae8aa1c7 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineActivities.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineActivities.tsx @@ -2,9 +2,9 @@ import styled from '@emotion/styled'; import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader'; import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; -import { EventList } from '@/activities/timelineActivities/components/EventList'; -import { TimelineCreateButtonGroup } from '@/activities/timelineActivities/components/TimelineCreateButtonGroup'; -import { useTimelineActivities } from '@/activities/timelineActivities/hooks/useTimelineActivities'; +import { EventList } from '@/activities/timeline-activities/components/EventList'; +import { TimelineCreateButtonGroup } from '@/activities/timeline-activities/components/TimelineCreateButtonGroup'; +import { useTimelineActivities } from '@/activities/timeline-activities/hooks/useTimelineActivities'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder'; import { @@ -46,7 +46,7 @@ export const TimelineActivities = ({ const isTimelineActivitiesEmpty = !timelineActivities || timelineActivities.length === 0; - if (loading) { + if (loading === true) { return ; } diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineCreateButtonGroup.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCreateButtonGroup.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineCreateButtonGroup.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCreateButtonGroup.tsx diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/__stories__/TimelineActivities.stories.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/__stories__/TimelineActivities.stories.tsx similarity index 89% rename from packages/twenty-front/src/modules/activities/timelineActivities/__stories__/TimelineActivities.stories.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/components/__stories__/TimelineActivities.stories.tsx index d04d8281c761..7c16632eea75 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/__stories__/TimelineActivities.stories.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/__stories__/TimelineActivities.stories.tsx @@ -1,9 +1,9 @@ import { Meta, StoryObj } from '@storybook/react'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { ComponentDecorator } from 'twenty-ui'; -import { TimelineActivities } from '@/activities/timelineActivities/components/TimelineActivities'; -import { TimelineActivityContext } from '@/activities/timelineActivities/contexts/TimelineActivityContext'; +import { TimelineActivities } from '@/activities/timeline-activities/components/TimelineActivities'; +import { TimelineActivityContext } from '@/activities/timeline-activities/contexts/TimelineActivityContext'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { mockedTimelineActivities } from '~/testing/mock-data/timeline-activities'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/constants/FindManyTimelineActivitiesOrderBy.ts b/packages/twenty-front/src/modules/activities/timeline-activities/constants/FindManyTimelineActivitiesOrderBy.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/constants/FindManyTimelineActivitiesOrderBy.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/constants/FindManyTimelineActivitiesOrderBy.ts diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/contexts/TimelineActivityContext.ts b/packages/twenty-front/src/modules/activities/timeline-activities/contexts/TimelineActivityContext.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/contexts/TimelineActivityContext.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/contexts/TimelineActivityContext.ts diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/hooks/__tests__/useTimelineActivities.test.tsx similarity index 95% rename from packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/hooks/__tests__/useTimelineActivities.test.tsx index 2d1989cc68ea..158b628bee6a 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/hooks/__tests__/useTimelineActivities.test.tsx @@ -1,6 +1,6 @@ import { renderHook } from '@testing-library/react'; -import { useTimelineActivities } from '@/activities/timelineActivities/hooks/useTimelineActivities'; +import { useTimelineActivities } from '@/activities/timeline-activities/hooks/useTimelineActivities'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/useLinkedObjectObjectMetadataItem.ts b/packages/twenty-front/src/modules/activities/timeline-activities/hooks/useLinkedObjectObjectMetadataItem.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/hooks/useLinkedObjectObjectMetadataItem.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/hooks/useLinkedObjectObjectMetadataItem.ts diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/useLinkedObjectsTitle.ts b/packages/twenty-front/src/modules/activities/timeline-activities/hooks/useLinkedObjectsTitle.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/hooks/useLinkedObjectsTitle.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/hooks/useLinkedObjectsTitle.ts diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/useTimelineActivities.ts b/packages/twenty-front/src/modules/activities/timeline-activities/hooks/useTimelineActivities.ts similarity index 90% rename from packages/twenty-front/src/modules/activities/timelineActivities/hooks/useTimelineActivities.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/hooks/useTimelineActivities.ts index fb65053c151c..96c00233e6d8 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/useTimelineActivities.ts +++ b/packages/twenty-front/src/modules/activities/timeline-activities/hooks/useTimelineActivities.ts @@ -1,5 +1,5 @@ -import { useLinkedObjectsTitle } from '@/activities/timelineActivities/hooks/useLinkedObjectsTitle'; -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { useLinkedObjectsTitle } from '@/activities/timeline-activities/hooks/useLinkedObjectsTitle'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/activity/components/EventRowActivity.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/activity/components/EventRowActivity.tsx similarity index 96% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/activity/components/EventRowActivity.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/activity/components/EventRowActivity.tsx index 1c1f34e43ade..24322ac7c598 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/activity/components/EventRowActivity.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/activity/components/EventRowActivity.tsx @@ -5,7 +5,7 @@ import { EventRowDynamicComponentProps, StyledEventRowItemAction, StyledEventRowItemColumn, -} from '@/activities/timelineActivities/rows/components/EventRowDynamicComponent'; +} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; import { isNonEmptyString } from '@sniptt/guards'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventCardCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventCardCalendarEvent.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventRowCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent.tsx similarity index 77% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventRowCalendarEvent.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent.tsx index c1ffd1094ef3..a4172b8f4a90 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventRowCalendarEvent.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent.tsx @@ -1,14 +1,14 @@ -import { useState } from 'react'; import styled from '@emotion/styled'; +import { useState } from 'react'; -import { EventCardCalendarEvent } from '@/activities/timelineActivities/rows/calendar/components/EventCardCalendarEvent'; -import { EventCard } from '@/activities/timelineActivities/rows/components/EventCard'; -import { EventCardToggleButton } from '@/activities/timelineActivities/rows/components/EventCardToggleButton'; +import { EventCardCalendarEvent } from '@/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent'; +import { EventCard } from '@/activities/timeline-activities/rows/components/EventCard'; +import { EventCardToggleButton } from '@/activities/timeline-activities/rows/components/EventCardToggleButton'; import { EventRowDynamicComponentProps, StyledEventRowItemAction, StyledEventRowItemColumn, -} from '@/activities/timelineActivities/rows/components/EventRowDynamicComponent'; +} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; type EventRowCalendarEventProps = EventRowDynamicComponentProps; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/__stories__/EventCardCalendarEvent.stories.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/__stories__/EventCardCalendarEvent.stories.tsx similarity index 90% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/__stories__/EventCardCalendarEvent.stories.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/__stories__/EventCardCalendarEvent.stories.tsx index b0c3fd7ca54c..8e8f4b3aaa0b 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/__stories__/EventCardCalendarEvent.stories.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/__stories__/EventCardCalendarEvent.stories.tsx @@ -1,8 +1,8 @@ import { Meta, StoryObj } from '@storybook/react'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { ComponentDecorator } from 'twenty-ui'; -import { EventCardCalendarEvent } from '@/activities/timelineActivities/rows/calendar/components/EventCardCalendarEvent'; +import { EventCardCalendarEvent } from '@/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventCard.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCard.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventCard.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCard.tsx diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventCardToggleButton.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCardToggleButton.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventCardToggleButton.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCardToggleButton.tsx diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventIconDynamicComponent.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventIconDynamicComponent.tsx similarity index 88% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventIconDynamicComponent.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventIconDynamicComponent.tsx index ecb7bc90d51f..6e4b49b8feea 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventIconDynamicComponent.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventIconDynamicComponent.tsx @@ -1,6 +1,6 @@ import { IconCirclePlus, IconEditCircle, IconTrash, useIcons } from 'twenty-ui'; -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; export const EventIconDynamicComponent = ({ diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventRowDynamicComponent.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventRowDynamicComponent.tsx similarity index 84% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventRowDynamicComponent.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventRowDynamicComponent.tsx index e5542cd35480..441d6598a841 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventRowDynamicComponent.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventRowDynamicComponent.tsx @@ -1,10 +1,10 @@ import styled from '@emotion/styled'; -import { EventRowActivity } from '@/activities/timelineActivities/rows/activity/components/EventRowActivity'; -import { EventRowCalendarEvent } from '@/activities/timelineActivities/rows/calendar/components/EventRowCalendarEvent'; -import { EventRowMainObject } from '@/activities/timelineActivities/rows/main-object/components/EventRowMainObject'; -import { EventRowMessage } from '@/activities/timelineActivities/rows/message/components/EventRowMessage'; -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { EventRowActivity } from '@/activities/timeline-activities/rows/activity/components/EventRowActivity'; +import { EventRowCalendarEvent } from '@/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent'; +import { EventRowMainObject } from '@/activities/timeline-activities/rows/main-object/components/EventRowMainObject'; +import { EventRowMessage } from '@/activities/timeline-activities/rows/message/components/EventRowMessage'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiff.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiff.tsx similarity index 88% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiff.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiff.tsx index 94726465f201..f1a50f9128e7 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiff.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiff.tsx @@ -1,8 +1,8 @@ import styled from '@emotion/styled'; -import { EventFieldDiffLabel } from '@/activities/timelineActivities/rows/main-object/components/EventFieldDiffLabel'; -import { EventFieldDiffValue } from '@/activities/timelineActivities/rows/main-object/components/EventFieldDiffValue'; -import { EventFieldDiffValueEffect } from '@/activities/timelineActivities/rows/main-object/components/EventFieldDiffValueEffect'; +import { EventFieldDiffLabel } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiffLabel'; +import { EventFieldDiffValue } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiffValue'; +import { EventFieldDiffValueEffect } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffContainer.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffContainer.tsx similarity index 91% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffContainer.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffContainer.tsx index 3b4cf60396f8..3a5b36ee6f44 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffContainer.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffContainer.tsx @@ -1,4 +1,4 @@ -import { EventFieldDiff } from '@/activities/timelineActivities/rows/main-object/components/EventFieldDiff'; +import { EventFieldDiff } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiff'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffLabel.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffLabel.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffLabel.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffLabel.tsx diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffValue.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValue.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffValue.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValue.tsx diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffValueEffect.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventFieldDiffValueEffect.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect.tsx diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObject.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObject.tsx similarity index 91% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObject.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObject.tsx index 053e9217bb66..448879073a1b 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObject.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObject.tsx @@ -1,11 +1,10 @@ -import styled from '@emotion/styled'; - import { EventRowDynamicComponentProps, StyledEventRowItemAction, StyledEventRowItemColumn, -} from '@/activities/timelineActivities/rows/components/EventRowDynamicComponent'; -import { EventRowMainObjectUpdated } from '@/activities/timelineActivities/rows/main-object/components/EventRowMainObjectUpdated'; +} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; +import { EventRowMainObjectUpdated } from '@/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated'; +import styled from '@emotion/styled'; type EventRowMainObjectProps = EventRowDynamicComponentProps; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObjectUpdated.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated.tsx similarity index 84% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObjectUpdated.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated.tsx index 30e6343bd708..cc2b7102e0d1 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObjectUpdated.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated.tsx @@ -1,14 +1,14 @@ -import { useState } from 'react'; import styled from '@emotion/styled'; +import { useState } from 'react'; -import { EventCard } from '@/activities/timelineActivities/rows/components/EventCard'; -import { EventCardToggleButton } from '@/activities/timelineActivities/rows/components/EventCardToggleButton'; +import { EventCard } from '@/activities/timeline-activities/rows/components/EventCard'; +import { EventCardToggleButton } from '@/activities/timeline-activities/rows/components/EventCardToggleButton'; import { StyledEventRowItemAction, StyledEventRowItemColumn, -} from '@/activities/timelineActivities/rows/components/EventRowDynamicComponent'; -import { EventFieldDiffContainer } from '@/activities/timelineActivities/rows/main-object/components/EventFieldDiffContainer'; -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; +import { EventFieldDiffContainer } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiffContainer'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx similarity index 90% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx index fe0b549d68da..d4a12a465643 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx @@ -1,8 +1,8 @@ +import { EventRowMainObjectUpdated } from '@/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { Meta, StoryObj } from '@storybook/react'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui'; -import { EventRowMainObjectUpdated } from '@/activities/timelineActivities/rows/main-object/components/EventRowMainObjectUpdated'; -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessage.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessage.tsx similarity index 98% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessage.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessage.tsx index 899c0414e76b..7114bd427667 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessage.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessage.tsx @@ -4,7 +4,7 @@ import { OverflowingTextWithTooltip } from 'twenty-ui'; import { useEmailThread } from '@/activities/emails/hooks/useEmailThread'; import { EmailThreadMessage } from '@/activities/emails/types/EmailThreadMessage'; -import { EventCardMessageNotShared } from '@/activities/timelineActivities/rows/message/components/EventCardMessageNotShared'; +import { EventCardMessageNotShared } from '@/activities/timeline-activities/rows/message/components/EventCardMessageNotShared'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessageNotShared.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageNotShared.tsx similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessageNotShared.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageNotShared.tsx diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventRowMessage.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventRowMessage.tsx similarity index 79% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventRowMessage.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventRowMessage.tsx index 83513994517f..00bd68e93a2a 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventRowMessage.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventRowMessage.tsx @@ -1,14 +1,14 @@ -import { useState } from 'react'; import styled from '@emotion/styled'; +import { useState } from 'react'; -import { EventCard } from '@/activities/timelineActivities/rows/components/EventCard'; -import { EventCardToggleButton } from '@/activities/timelineActivities/rows/components/EventCardToggleButton'; +import { EventCard } from '@/activities/timeline-activities/rows/components/EventCard'; +import { EventCardToggleButton } from '@/activities/timeline-activities/rows/components/EventCardToggleButton'; import { EventRowDynamicComponentProps, StyledEventRowItemAction, StyledEventRowItemColumn, -} from '@/activities/timelineActivities/rows/components/EventRowDynamicComponent'; -import { EventCardMessage } from '@/activities/timelineActivities/rows/message/components/EventCardMessage'; +} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; +import { EventCardMessage } from '@/activities/timeline-activities/rows/message/components/EventCardMessage'; type EventRowMessageProps = EventRowDynamicComponentProps; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/__stories__/EventCardMessage.stories.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/__stories__/EventCardMessage.stories.tsx similarity index 87% rename from packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/__stories__/EventCardMessage.stories.tsx rename to packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/__stories__/EventCardMessage.stories.tsx index 3e8e08cd06dc..40d27298fd5d 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/__stories__/EventCardMessage.stories.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/__stories__/EventCardMessage.stories.tsx @@ -1,9 +1,9 @@ import { Meta, StoryObj } from '@storybook/react'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { ComponentDecorator } from 'twenty-ui'; -import { TimelineActivityContext } from '@/activities/timelineActivities/contexts/TimelineActivityContext'; -import { EventCardMessage } from '@/activities/timelineActivities/rows/message/components/EventCardMessage'; +import { TimelineActivityContext } from '@/activities/timeline-activities/contexts/TimelineActivityContext'; +import { EventCardMessage } from '@/activities/timeline-activities/rows/message/components/EventCardMessage'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/states/objectShowPageTargetableObjectIdState.ts b/packages/twenty-front/src/modules/activities/timeline-activities/states/objectShowPageTargetableObjectIdState.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/states/objectShowPageTargetableObjectIdState.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/states/objectShowPageTargetableObjectIdState.ts diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/types/TimelineActivity.ts b/packages/twenty-front/src/modules/activities/timeline-activities/types/TimelineActivity.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/types/TimelineActivity.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/types/TimelineActivity.ts diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/types/TimelineActivityLinkedObject.ts b/packages/twenty-front/src/modules/activities/timeline-activities/types/TimelineActivityLinkedObject.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/types/TimelineActivityLinkedObject.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/types/TimelineActivityLinkedObject.ts diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts b/packages/twenty-front/src/modules/activities/timeline-activities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts similarity index 96% rename from packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts index 1dc11441002b..a685d15055c5 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts +++ b/packages/twenty-front/src/modules/activities/timeline-activities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts @@ -1,5 +1,5 @@ -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; -import { filterOutInvalidTimelineActivities } from '@/activities/timelineActivities/utils/filterOutInvalidTimelineActivities'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; +import { filterOutInvalidTimelineActivities } from '@/activities/timeline-activities/utils/filterOutInvalidTimelineActivities'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/getTimelineActivityAuthorFullName.test.ts b/packages/twenty-front/src/modules/activities/timeline-activities/utils/__tests__/getTimelineActivityAuthorFullName.test.ts similarity index 91% rename from packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/getTimelineActivityAuthorFullName.test.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/utils/__tests__/getTimelineActivityAuthorFullName.test.ts index 85ac636ea096..7b3d817c64e0 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/getTimelineActivityAuthorFullName.test.ts +++ b/packages/twenty-front/src/modules/activities/timeline-activities/utils/__tests__/getTimelineActivityAuthorFullName.test.ts @@ -1,5 +1,5 @@ -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; -import { getTimelineActivityAuthorFullName } from '@/activities/timelineActivities/utils/getTimelineActivityAuthorFullName'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; +import { getTimelineActivityAuthorFullName } from '@/activities/timeline-activities/utils/getTimelineActivityAuthorFullName'; import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState'; describe('getTimelineActivityAuthorFullName', () => { diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/groupEventsByMonth.test.ts b/packages/twenty-front/src/modules/activities/timeline-activities/utils/__tests__/groupEventsByMonth.test.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/groupEventsByMonth.test.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/utils/__tests__/groupEventsByMonth.test.ts diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/filterOutInvalidTimelineActivities.ts b/packages/twenty-front/src/modules/activities/timeline-activities/utils/filterOutInvalidTimelineActivities.ts similarity index 95% rename from packages/twenty-front/src/modules/activities/timelineActivities/utils/filterOutInvalidTimelineActivities.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/utils/filterOutInvalidTimelineActivities.ts index 5613db9d48b0..96413c89cd4e 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/utils/filterOutInvalidTimelineActivities.ts +++ b/packages/twenty-front/src/modules/activities/timeline-activities/utils/filterOutInvalidTimelineActivities.ts @@ -1,4 +1,4 @@ -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/filterTimelineActivityByLinkedObjectTypes.ts b/packages/twenty-front/src/modules/activities/timeline-activities/utils/filterTimelineActivityByLinkedObjectTypes.ts similarity index 75% rename from packages/twenty-front/src/modules/activities/timelineActivities/utils/filterTimelineActivityByLinkedObjectTypes.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/utils/filterTimelineActivityByLinkedObjectTypes.ts index 455ceca01c0a..781e85d8b67e 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/utils/filterTimelineActivityByLinkedObjectTypes.ts +++ b/packages/twenty-front/src/modules/activities/timeline-activities/utils/filterTimelineActivityByLinkedObjectTypes.ts @@ -1,5 +1,5 @@ -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; -import { TimelineActivityLinkedObject } from '@/activities/timelineActivities/types/TimelineActivityLinkedObject'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; +import { TimelineActivityLinkedObject } from '@/activities/timeline-activities/types/TimelineActivityLinkedObject'; export const filterTimelineActivityByLinkedObjectTypes = (linkedObjectTypes: TimelineActivityLinkedObject[]) => diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/getTimelineActivityAuthorFullName.ts b/packages/twenty-front/src/modules/activities/timeline-activities/utils/getTimelineActivityAuthorFullName.ts similarity index 84% rename from packages/twenty-front/src/modules/activities/timelineActivities/utils/getTimelineActivityAuthorFullName.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/utils/getTimelineActivityAuthorFullName.ts index e97b27fa9450..4e141de6b3bd 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/utils/getTimelineActivityAuthorFullName.ts +++ b/packages/twenty-front/src/modules/activities/timeline-activities/utils/getTimelineActivityAuthorFullName.ts @@ -1,4 +1,4 @@ -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/groupEventsByMonth.ts b/packages/twenty-front/src/modules/activities/timeline-activities/utils/groupEventsByMonth.ts similarity index 89% rename from packages/twenty-front/src/modules/activities/timelineActivities/utils/groupEventsByMonth.ts rename to packages/twenty-front/src/modules/activities/timeline-activities/utils/groupEventsByMonth.ts index fa0779f538c3..cd5ce8a73364 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/utils/groupEventsByMonth.ts +++ b/packages/twenty-front/src/modules/activities/timeline-activities/utils/groupEventsByMonth.ts @@ -1,4 +1,4 @@ -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { isDefined } from '~/utils/isDefined'; export type EventGroup = { diff --git a/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts b/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts index 65f69f6d290e..6eca2c821fc6 100644 --- a/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts +++ b/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts @@ -18,7 +18,7 @@ import { logDebug } from '~/utils/logDebug'; import { GraphQLFormattedError } from 'graphql'; import { ApolloManager } from '../types/apolloManager.interface'; -import { loggerLink } from '../utils'; +import { loggerLink } from '../utils/loggerLink'; const logger = loggerLink(() => 'Twenty'); diff --git a/packages/twenty-front/src/modules/apollo/utils/__tests__/format-title.test.ts b/packages/twenty-front/src/modules/apollo/utils/__tests__/formatTitle.test.ts similarity index 91% rename from packages/twenty-front/src/modules/apollo/utils/__tests__/format-title.test.ts rename to packages/twenty-front/src/modules/apollo/utils/__tests__/formatTitle.test.ts index 39773acb8dda..47d8dc2ae8e2 100644 --- a/packages/twenty-front/src/modules/apollo/utils/__tests__/format-title.test.ts +++ b/packages/twenty-front/src/modules/apollo/utils/__tests__/formatTitle.test.ts @@ -2,7 +2,7 @@ import { expect } from '@storybook/test'; import { OperationType } from '@/apollo/types/operation-type'; -import formatTitle from '../format-title'; +import formatTitle from '../formatTitle'; describe('formatTitle', () => { it('should correctly format the title', () => { diff --git a/packages/twenty-front/src/modules/apollo/utils/__tests__/utils.test.ts b/packages/twenty-front/src/modules/apollo/utils/__tests__/utils.test.ts deleted file mode 100644 index 0d87baac9971..000000000000 --- a/packages/twenty-front/src/modules/apollo/utils/__tests__/utils.test.ts +++ /dev/null @@ -1,4 +0,0 @@ -// More work needed here -describe.skip('loggerLink', () => { - it('should log the correct message', () => {}); -}); diff --git a/packages/twenty-front/src/modules/apollo/utils/format-title.ts b/packages/twenty-front/src/modules/apollo/utils/formatTitle.ts similarity index 100% rename from packages/twenty-front/src/modules/apollo/utils/format-title.ts rename to packages/twenty-front/src/modules/apollo/utils/formatTitle.ts diff --git a/packages/twenty-front/src/modules/apollo/utils/index.ts b/packages/twenty-front/src/modules/apollo/utils/loggerLink.ts similarity index 98% rename from packages/twenty-front/src/modules/apollo/utils/index.ts rename to packages/twenty-front/src/modules/apollo/utils/loggerLink.ts index b57f427cf192..174c5c3badda 100644 --- a/packages/twenty-front/src/modules/apollo/utils/index.ts +++ b/packages/twenty-front/src/modules/apollo/utils/loggerLink.ts @@ -4,7 +4,7 @@ import { isDefined } from '~/utils/isDefined'; import { logDebug } from '~/utils/logDebug'; import { logError } from '~/utils/logError'; -import formatTitle from './format-title'; +import formatTitle from './formatTitle'; const getGroup = (collapsed: boolean) => collapsed diff --git a/packages/twenty-front/src/modules/app/components/AppRouter.tsx b/packages/twenty-front/src/modules/app/components/AppRouter.tsx index d8985e676332..9e474de5ad44 100644 --- a/packages/twenty-front/src/modules/app/components/AppRouter.tsx +++ b/packages/twenty-front/src/modules/app/components/AppRouter.tsx @@ -1,4 +1,4 @@ -import { createAppRouter } from '@/app/utils/createAppRouter'; +import { useCreateAppRouter } from '@/app/hooks/useCreateAppRouter'; import { billingState } from '@/client-config/states/billingState'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { RouterProvider } from 'react-router-dom'; @@ -17,7 +17,7 @@ export const AppRouter = () => { return ( { const apolloMetadataClient = useContext(ApolloMetadataClientContext); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.ts similarity index 100% rename from packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx rename to packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.ts diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.ts similarity index 100% rename from packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx rename to packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.ts diff --git a/packages/twenty-front/src/modules/object-record/hooks/useRecordChipData.ts b/packages/twenty-front/src/modules/object-record/hooks/useRecordChipData.ts index 1958a09eb535..7ade7cb90699 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useRecordChipData.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useRecordChipData.ts @@ -1,4 +1,4 @@ -import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext'; import { generateDefaultRecordChipData } from '@/object-metadata/utils/generateDefaultRecordChipData'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { useContext } from 'react'; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx index 3961f28c836b..f464b8710f91 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx @@ -6,12 +6,12 @@ import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue'; import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; -import { computeVariableDateViewFilterValue } from '@/views/utils/view-filter-value/computeVariableDateViewFilterValue'; +import { computeVariableDateViewFilterValue } from '@/views/view-filter-value/utils/computeVariableDateViewFilterValue'; import { VariableDateViewFilterValueDirection, VariableDateViewFilterValueUnit, -} from '@/views/utils/view-filter-value/resolveDateViewFilterValue'; -import { resolveFilterValue } from '@/views/utils/view-filter-value/resolveFilterValue'; +} from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; +import { resolveFilterValue } from '@/views/view-filter-value/utils/resolveFilterValue'; import { useState } from 'react'; import { isDefined } from 'twenty-ui'; import { FieldMetadataType } from '~/generated-metadata/graphql'; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandLabel.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandLabel.test.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandLabel.test.tsx rename to packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandLabel.test.ts diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx rename to packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue.ts index fb59e540180b..9bbc69af3f52 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue.ts @@ -1,7 +1,7 @@ import { VariableDateViewFilterValueDirection, VariableDateViewFilterValueUnit, -} from '@/views/utils/view-filter-value/resolveDateViewFilterValue'; +} from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; import { plural } from 'pluralize'; import { capitalize } from '~/utils/string/capitalize'; export const getRelativeDateDisplayValue = ( diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/turnSortsIntoOrderBy.test.tsx b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/turnSortsIntoOrderBy.test.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/turnSortsIntoOrderBy.test.tsx rename to packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/turnSortsIntoOrderBy.test.ts diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx index e9487ea6eb23..01ca2843c3bb 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -11,7 +11,7 @@ import { useRecordBoardStates } from '@/object-record/record-board/hooks/interna import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection'; import { RecordBoardColumn } from '@/object-record/record-board/record-board-column/components/RecordBoardColumn'; import { RecordBoardScope } from '@/object-record/record-board/scopes/RecordBoardScope'; -import { getDraggedRecordPosition } from '@/object-record/record-board/utils/get-dragged-record-position.util'; +import { getDraggedRecordPosition } from '@/object-record/record-board/utils/getDraggedRecordPosition'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; diff --git a/packages/twenty-front/src/modules/object-record/record-board/utils/__tests__/get-dragged-record-position.util.test.ts b/packages/twenty-front/src/modules/object-record/record-board/utils/__tests__/getDraggedRecordPosition.test.ts similarity index 92% rename from packages/twenty-front/src/modules/object-record/record-board/utils/__tests__/get-dragged-record-position.util.test.ts rename to packages/twenty-front/src/modules/object-record/record-board/utils/__tests__/getDraggedRecordPosition.test.ts index 1359c2d597be..483c323f07c6 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/utils/__tests__/get-dragged-record-position.util.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/utils/__tests__/getDraggedRecordPosition.test.ts @@ -1,4 +1,4 @@ -import { getDraggedRecordPosition } from '../get-dragged-record-position.util'; +import { getDraggedRecordPosition } from '../getDraggedRecordPosition'; describe('getDraggedRecordPosition', () => { it('when both records defined and positive, should return the average of the two positions', () => { diff --git a/packages/twenty-front/src/modules/object-record/record-board/utils/get-dragged-record-position.util.ts b/packages/twenty-front/src/modules/object-record/record-board/utils/getDraggedRecordPosition.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/record-board/utils/get-dragged-record-position.util.ts rename to packages/twenty-front/src/modules/object-record/record-board/utils/getDraggedRecordPosition.ts diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/__stories__/FieldContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/components/FieldContextProvider.tsx similarity index 100% rename from packages/twenty-front/src/modules/object-record/record-field/meta-types/__stories__/FieldContextProvider.tsx rename to packages/twenty-front/src/modules/object-record/record-field/meta-types/components/FieldContextProvider.tsx diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts index 6451634ef5d7..6569e987c38f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts @@ -1,7 +1,7 @@ import { isNonEmptyString } from '@sniptt/guards'; import { useContext } from 'react'; -import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext'; import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName'; import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber'; import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay.ts index 760a70b987ea..aec21e44b0d3 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay.ts @@ -1,7 +1,7 @@ -import { useContext } from 'react'; import { isNonEmptyString } from '@sniptt/guards'; +import { useContext } from 'react'; -import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext'; import { generateDefaultRecordChipData } from '@/object-metadata/utils/generateDefaultRecordChipData'; import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationToOneFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationToOneFieldDisplay.ts index 85afbd90743d..ff380aff3e81 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationToOneFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationToOneFieldDisplay.ts @@ -1,7 +1,7 @@ -import { useContext } from 'react'; import { isNonEmptyString } from '@sniptt/guards'; +import { useContext } from 'react'; -import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext'; import { generateDefaultRecordChipData } from '@/object-metadata/utils/generateDefaultRecordChipData'; import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/AddressFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/AddressFieldInput.stories.tsx index be1a3cefa206..2cda4b62cb05 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/AddressFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/AddressFieldInput.stories.tsx @@ -1,6 +1,6 @@ -import { useEffect } from 'react'; import { Decorator, Meta, StoryObj } from '@storybook/react'; import { expect, fn, userEvent, waitFor } from '@storybook/test'; +import { useEffect } from 'react'; import { useAddressField } from '@/object-record/record-field/meta-types/hooks/useAddressField'; import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue'; @@ -11,7 +11,7 @@ import { import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { FieldMetadataType } from '~/generated-metadata/graphql'; -import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; +import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider'; const AddressValueSetterEffect = ({ value, diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx index 3b6f3300b530..764dca8fa480 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx @@ -1,12 +1,12 @@ -import { useEffect } from 'react'; import { Meta, StoryObj } from '@storybook/react'; import { expect, fn, userEvent, within } from '@storybook/test'; +import { useEffect } from 'react'; import { useSetRecoilState } from 'recoil'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { FieldMetadataType } from '~/generated/graphql'; -import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; +import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider'; import { BooleanFieldInput, BooleanFieldInputProps, diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx index 4c6c0d19a15f..c2155357971c 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx @@ -1,11 +1,11 @@ -import { useEffect } from 'react'; import { Meta, StoryObj } from '@storybook/react'; import { expect, fn, userEvent, within } from '@storybook/test'; +import { useEffect } from 'react'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { FieldMetadataType } from '~/generated/graphql'; -import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; +import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider'; import { useDateTimeField } from '../../../hooks/useDateTimeField'; import { DateTimeFieldInput, diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/NumberFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/NumberFieldInput.stories.tsx index 79d32f974ae6..e0b8e85bd5ca 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/NumberFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/NumberFieldInput.stories.tsx @@ -1,12 +1,12 @@ -import { useEffect } from 'react'; import { Decorator, Meta, StoryObj } from '@storybook/react'; import { expect, fn, userEvent, waitFor, within } from '@storybook/test'; +import { useEffect } from 'react'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { FieldMetadataType } from '~/generated/graphql'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; -import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; +import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider'; import { useNumberField } from '../../../hooks/useNumberField'; import { NumberFieldInput, NumberFieldInputProps } from '../NumberFieldInput'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RatingFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RatingFieldInput.stories.tsx index 5317c6ec36f5..dddbfbfc84d9 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RatingFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RatingFieldInput.stories.tsx @@ -1,13 +1,13 @@ -import { useEffect } from 'react'; import { Decorator, Meta, StoryObj } from '@storybook/react'; import { expect, fn, userEvent, waitFor, within } from '@storybook/test'; +import { useEffect } from 'react'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDefined } from '~/utils/isDefined'; +import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider'; import { FieldRatingValue } from '../../../../types/FieldMetadata'; -import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; import { useRatingField } from '../../../hooks/useRatingField'; import { RatingFieldInput, RatingFieldInputProps } from '../RatingFieldInput'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx index 97f8f7e206e7..3a4cd095e1fa 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx @@ -1,5 +1,5 @@ -import { useEffect } from 'react'; import { Meta, StoryObj } from '@storybook/react'; +import { useEffect } from 'react'; import { useSetRecoilState } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; @@ -17,7 +17,7 @@ import { mockedWorkspaceMemberData, } from '~/testing/mock-data/users'; -import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; +import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider'; const RelationWorkspaceSetterEffect = () => { const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx index 09c405061fb7..6bb6f02d2b03 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx @@ -25,7 +25,7 @@ import { mockedWorkspaceMemberData, } from '~/testing/mock-data/users'; -import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; +import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider'; import { RelationToOneFieldInput, RelationToOneFieldInputProps, diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/TextFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/TextFieldInput.stories.tsx index ef9bdced6a5c..ec17c5ff92a3 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/TextFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/TextFieldInput.stories.tsx @@ -1,12 +1,12 @@ -import { useEffect } from 'react'; import { Decorator, Meta, StoryObj } from '@storybook/react'; import { expect, fn, userEvent, waitFor, within } from '@storybook/test'; +import { useEffect } from 'react'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { FieldMetadataType } from '~/generated/graphql'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; -import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; +import { FieldContextProvider } from '../../../components/FieldContextProvider'; import { useTextField } from '../../../hooks/useTextField'; import { TextFieldInput, TextFieldInputProps } from '../TextFieldInput'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/utils/getFieldButtonIcon.tsx b/packages/twenty-front/src/modules/object-record/record-field/utils/getFieldButtonIcon.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/record-field/utils/getFieldButtonIcon.tsx rename to packages/twenty-front/src/modules/object-record/record-field/utils/getFieldButtonIcon.ts diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts index ff0199344948..345421f7ce95 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts @@ -25,7 +25,7 @@ import { } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { applyEmptyFilters } from '@/object-record/record-filter/utils/applyEmptyFilters'; -import { resolveFilterValue } from '@/views/utils/view-filter-value/resolveFilterValue'; +import { resolveFilterValue } from '@/views/view-filter-value/utils/resolveFilterValue'; import { endOfDay, roundToNearestMinutes, startOfDay } from 'date-fns'; import { z } from 'zod'; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx index f167ad13f19d..60ab0fed8afc 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx @@ -6,9 +6,9 @@ import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetada import { RecordIndexPageKanbanAddButton } from '@/object-record/record-index/components/RecordIndexPageKanbanAddButton'; import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState'; -import { PageAddButton } from '@/ui/layout/page/PageAddButton'; -import { PageHeader } from '@/ui/layout/page/PageHeader'; -import { PageHotkeysEffect } from '@/ui/layout/page/PageHotkeysEffect'; +import { PageAddButton } from '@/ui/layout/page/components/PageAddButton'; +import { PageHeader } from '@/ui/layout/page/components/PageHeader'; +import { PageHotkeysEffect } from '@/ui/layout/page/components/PageHotkeysEffect'; import { ViewType } from '@/views/types/ViewType'; import { useContext } from 'react'; import { capitalize } from '~/utils/string/capitalize'; diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx index 8e911edac10c..01e5f42d6592 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx @@ -1,6 +1,6 @@ import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { ShowPageContainer } from '@/ui/layout/page/ShowPageContainer'; +import { ShowPageContainer } from '@/ui/layout/page/components/ShowPageContainer'; import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData'; import { useRecordShowContainerTabs } from '@/object-record/record-show/hooks/useRecordShowContainerTabs'; diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2.ts b/packages/twenty-front/src/modules/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2.ts index 9cd066b84e5e..a30216912c08 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2.ts @@ -1,5 +1,5 @@ import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; -import { createComponentStateV2_alpha } from '@/ui/utilities/state/component-state/utils/createComponentStateV2_alpha'; +import { createComponentStateV2_alpha } from '@/ui/utilities/state/component-state/utils/createComponentStateV2Alpha'; export const hasRecordTableFetchedAllRecordsComponentStateV2 = createComponentStateV2_alpha({ diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts index b51a7f63f48d..a11aa2eb789e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts @@ -1,5 +1,5 @@ import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; -import { createComponentStateV2_alpha } from '@/ui/utilities/state/component-state/utils/createComponentStateV2_alpha'; +import { createComponentStateV2_alpha } from '@/ui/utilities/state/component-state/utils/createComponentStateV2Alpha'; export const isRecordTableScrolledLeftComponentState = createComponentStateV2_alpha({ diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.tsx b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.ts similarity index 98% rename from packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.tsx rename to packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.ts index a7e47f8ba713..0eacdbb3d5ae 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.tsx +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.ts @@ -6,8 +6,9 @@ import { useRecoilValue } from 'recoil'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState'; +import { useOpenObjectRecordsSpreasheetImportDialog } from '@/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreasheetImportDialog'; + import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; -import { useOpenObjectRecordsSpreasheetImportDialog } from '../hooks/useOpenObjectRecordsSpreasheetImportDialog'; const companyId = 'cb2e9f4b-20c3-4759-9315-4ffeecfaf71a'; diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useBuildAvailableFieldsForImport.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useBuildAvailableFieldsForImport.ts index 260a223f1791..21cbdb3f9ee0 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useBuildAvailableFieldsForImport.ts +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useBuildAvailableFieldsForImport.ts @@ -4,7 +4,7 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { COMPOSITE_FIELD_IMPORT_LABELS } from '@/object-record/spreadsheet-import/constants/CompositeFieldImportLabels'; import { AvailableFieldForImport } from '@/object-record/spreadsheet-import/types/AvailableFieldForImport'; -import { getSpreadSheetFieldValidationDefinitions } from '@/object-record/spreadsheet-import/util/getSpreadSheetFieldValidationDefinitions'; +import { getSpreadSheetFieldValidationDefinitions } from '@/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions'; import { FieldMetadataType } from '~/generated-metadata/graphql'; export const useBuildAvailableFieldsForImport = () => { diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreasheetImportDialog.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreasheetImportDialog.ts index e5be43858442..d90dfff54842 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreasheetImportDialog.ts +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreasheetImportDialog.ts @@ -1,7 +1,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords'; import { useBuildAvailableFieldsForImport } from '@/object-record/spreadsheet-import/hooks/useBuildAvailableFieldsForImport'; -import { buildRecordFromImportedStructuredRow } from '@/object-record/spreadsheet-import/util/buildRecordFromImportedStructuredRow'; +import { buildRecordFromImportedStructuredRow } from '@/object-record/spreadsheet-import/utils/buildRecordFromImportedStructuredRow'; import { useOpenSpreadsheetImportDialog } from '@/spreadsheet-import/hooks/useOpenSpreadsheetImportDialog'; import { SpreadsheetImportDialogOptions } from '@/spreadsheet-import/types'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/util/buildRecordFromImportedStructuredRow.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/buildRecordFromImportedStructuredRow.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/spreadsheet-import/util/buildRecordFromImportedStructuredRow.ts rename to packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/buildRecordFromImportedStructuredRow.ts diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/util/getSpreadSheetFieldValidationDefinitions.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/spreadsheet-import/util/getSpreadSheetFieldValidationDefinitions.ts rename to packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts diff --git a/packages/twenty-front/src/modules/object-record/utils/__tests__/computeRecordBoardColumnDefinitionsFromObjectMetadata.test.ts b/packages/twenty-front/src/modules/object-record/utils/__tests__/computeRecordBoardColumnDefinitionsFromObjectMetadata.test.ts new file mode 100644 index 000000000000..98137b1df480 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/utils/__tests__/computeRecordBoardColumnDefinitionsFromObjectMetadata.test.ts @@ -0,0 +1,27 @@ +import { expect } from '@storybook/test'; + +import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; +import { computeRecordBoardColumnDefinitionsFromObjectMetadata } from '../computeRecordBoardColumnDefinitionsFromObjectMetadata'; + +describe('computeRecordBoardColumnDefinitionsFromObjectMetadata', () => { + it('should correctly compute', () => { + const objectMetadataItem = generatedMockObjectMetadataItems.find( + (item) => item.nameSingular === 'opportunity', + ); + + const stageField = objectMetadataItem?.fields.find( + (field) => field.name === 'stage', + ); + + if (!objectMetadataItem) { + throw new Error('Object metadata item not found'); + } + + const res = computeRecordBoardColumnDefinitionsFromObjectMetadata( + objectMetadataItem, + stageField?.id, + () => null, + ); + expect(res.length).toEqual(stageField?.options?.length); + }); +}); diff --git a/packages/twenty-front/src/modules/object-record/utils/getRecordChipGenerators.ts b/packages/twenty-front/src/modules/object-record/utils/getRecordChipGenerators.ts index fa56378afdd1..1ee8e850a2a3 100644 --- a/packages/twenty-front/src/modules/object-record/utils/getRecordChipGenerators.ts +++ b/packages/twenty-front/src/modules/object-record/utils/getRecordChipGenerators.ts @@ -1,7 +1,7 @@ import { ChipGeneratorPerObjectNameSingularPerFieldName, IdentifierChipGeneratorPerObject, -} from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +} from '@/object-metadata/contexts/PreComputedChipGeneratorsContext'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getAvatarType } from '@/object-metadata/utils/getAvatarType'; import { getAvatarUrl } from '@/object-metadata/utils/getAvatarUrl'; diff --git a/packages/twenty-front/src/modules/opportunities/Opportunity.ts b/packages/twenty-front/src/modules/opportunities/types/Opportunity.ts similarity index 100% rename from packages/twenty-front/src/modules/opportunities/Opportunity.ts rename to packages/twenty-front/src/modules/opportunities/types/Opportunity.ts diff --git a/packages/twenty-front/src/modules/prefetch/constants/PrefetchConfig.ts b/packages/twenty-front/src/modules/prefetch/constants/PrefetchConfig.ts index f76ba6637925..dd38928fcf64 100644 --- a/packages/twenty-front/src/modules/prefetch/constants/PrefetchConfig.ts +++ b/packages/twenty-front/src/modules/prefetch/constants/PrefetchConfig.ts @@ -1,7 +1,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { RecordGqlOperationSignatureFactory } from '@/object-record/graphql/types/RecordGqlOperationSignatureFactory'; -import { findAllFavoritesOperationSignatureFactory } from '@/prefetch/operation-signatures/factories/findAllFavoritesOperationSignatureFactory'; -import { findAllViewsOperationSignatureFactory } from '@/prefetch/operation-signatures/factories/findAllViewsOperationSignatureFactory'; +import { findAllFavoritesOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllFavoritesOperationSignatureFactory'; +import { findAllViewsOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllViewsOperationSignatureFactory'; import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; export const PREFETCH_CONFIG: Record< diff --git a/packages/twenty-front/src/modules/prefetch/operation-signatures/factories/findAllFavoritesOperationSignatureFactory.ts b/packages/twenty-front/src/modules/prefetch/graphql/operation-signatures/factories/findAllFavoritesOperationSignatureFactory.ts similarity index 100% rename from packages/twenty-front/src/modules/prefetch/operation-signatures/factories/findAllFavoritesOperationSignatureFactory.ts rename to packages/twenty-front/src/modules/prefetch/graphql/operation-signatures/factories/findAllFavoritesOperationSignatureFactory.ts diff --git a/packages/twenty-front/src/modules/prefetch/operation-signatures/factories/findAllViewsOperationSignatureFactory.ts b/packages/twenty-front/src/modules/prefetch/graphql/operation-signatures/factories/findAllViewsOperationSignatureFactory.ts similarity index 100% rename from packages/twenty-front/src/modules/prefetch/operation-signatures/factories/findAllViewsOperationSignatureFactory.ts rename to packages/twenty-front/src/modules/prefetch/graphql/operation-signatures/factories/findAllViewsOperationSignatureFactory.ts diff --git a/packages/twenty-front/src/modules/settings/components/SettingsSkeletonLoader.tsx b/packages/twenty-front/src/modules/settings/components/SettingsSkeletonLoader.tsx index 812a5ca67b82..1e9403a3aa69 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsSkeletonLoader.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsSkeletonLoader.tsx @@ -1,6 +1,6 @@ import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; -import { PageBody } from '@/ui/layout/page/PageBody'; -import { PageHeader } from '@/ui/layout/page/PageHeader'; +import { PageBody } from '@/ui/layout/page/components/PageBody'; +import { PageHeader } from '@/ui/layout/page/components/PageHeader'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard.tsx index 360c9a300692..c052e01ffb71 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard.tsx @@ -4,7 +4,7 @@ import { SettingsDataModelFieldPreview, SettingsDataModelFieldPreviewProps, } from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreview'; -import { SettingsDataModelObjectSummary } from '@/settings/data-model/objects/SettingsDataModelObjectSummary'; +import { SettingsDataModelObjectSummary } from '@/settings/data-model/objects/components/SettingsDataModelObjectSummary'; import { Card } from '@/ui/layout/card/components/Card'; import { CardContent } from '@/ui/layout/card/components/CardContent'; diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx index e5bd42d0b4e3..42f4fabd50ed 100644 --- a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx @@ -1,17 +1,17 @@ +import styled from '@emotion/styled'; import { useCallback, useState } from 'react'; import ReactFlow, { - applyEdgeChanges, - applyNodeChanges, Background, EdgeChange, + NodeChange, + applyEdgeChanges, + applyNodeChanges, getIncomers, getOutgoers, - NodeChange, useEdgesState, useNodesState, useReactFlow, } from 'reactflow'; -import styled from '@emotion/styled'; import { IconLock, IconLockOpen, @@ -24,7 +24,7 @@ import { import { SettingsDataModelOverviewEffect } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewEffect'; import { SettingsDataModelOverviewObject } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject'; import { SettingsDataModelOverviewRelationMarkers } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewRelationMarkers'; -import { calculateHandlePosition } from '@/settings/data-model/graph-overview/util/calculateHandlePosition'; +import { calculateHandlePosition } from '@/settings/data-model/graph-overview/utils/calculateHandlePosition'; import { Button } from '@/ui/input/button/components/Button'; import { IconButtonGroup } from '@/ui/input/button/components/IconButtonGroup'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx index 85c473b2fe36..593503fd2b97 100644 --- a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx @@ -8,7 +8,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { ObjectFieldRow } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewField'; -import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag'; +import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag'; import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; import { FieldMetadataType } from '~/generated/graphql'; import { capitalize } from '~/utils/string/capitalize'; diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/util/__tests__/calculateHandlePosition.test.ts b/packages/twenty-front/src/modules/settings/data-model/graph-overview/utils/__tests__/calculateHandlePosition.test.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/data-model/graph-overview/util/__tests__/calculateHandlePosition.test.ts rename to packages/twenty-front/src/modules/settings/data-model/graph-overview/utils/__tests__/calculateHandlePosition.test.ts diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/util/calculateHandlePosition.ts b/packages/twenty-front/src/modules/settings/data-model/graph-overview/utils/calculateHandlePosition.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/data-model/graph-overview/util/calculateHandlePosition.ts rename to packages/twenty-front/src/modules/settings/data-model/graph-overview/utils/calculateHandlePosition.ts diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx index 27e1a97823cd..1de7ea88adad 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx @@ -4,7 +4,7 @@ import { ReactNode } from 'react'; import { useIcons } from 'twenty-ui'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag'; +import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag'; import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectSummaryCard.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectSummaryCard.tsx index 6161fbcdf3a3..22ae24fdb0c0 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectSummaryCard.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectSummaryCard.tsx @@ -6,7 +6,7 @@ import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisi import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard'; -import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag'; +import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag'; import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectSummary.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsDataModelObjectSummary.tsx similarity index 96% rename from packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectSummary.tsx rename to packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsDataModelObjectSummary.tsx index 931fb6990e09..270ef7a28d26 100644 --- a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectSummary.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsDataModelObjectSummary.tsx @@ -3,7 +3,7 @@ import styled from '@emotion/styled'; import { OverflowingTextWithTooltip, useIcons } from 'twenty-ui'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag'; +import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag'; import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; export type SettingsDataModelObjectSummaryProps = { diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectTypeTag.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsDataModelObjectTypeTag.tsx similarity index 100% rename from packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectTypeTag.tsx rename to packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsDataModelObjectTypeTag.tsx diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsObjectCoverImage.tsx similarity index 91% rename from packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx rename to packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsObjectCoverImage.tsx index 87ce82a443ea..f2db34f27e38 100644 --- a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsObjectCoverImage.tsx @@ -5,8 +5,8 @@ import { FloatingButton } from '@/ui/input/button/components/FloatingButton'; import { Card } from '@/ui/layout/card/components/Card'; import { SettingsPath } from '@/types/SettingsPath'; -import DarkCoverImage from '../assets/cover-dark.png'; -import LightCoverImage from '../assets/cover-light.png'; +import DarkCoverImage from '../../assets/cover-dark.png'; +import LightCoverImage from '../../assets/cover-light.png'; const StyledCoverImageContainer = styled(Card)` align-items: center; diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectInactiveMenuDropDown.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsObjectInactiveMenuDropDown.tsx similarity index 100% rename from packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectInactiveMenuDropDown.tsx rename to packages/twenty-front/src/modules/settings/data-model/objects/components/SettingsObjectInactiveMenuDropDown.tsx diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/components/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx similarity index 100% rename from packages/twenty-front/src/modules/settings/data-model/objects/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx rename to packages/twenty-front/src/modules/settings/data-model/objects/components/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard.tsx index eec82eb8e394..4b2782b69d39 100644 --- a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard.tsx @@ -6,11 +6,11 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; import { SettingsDataModelCardTitle } from '@/settings/data-model/components/SettingsDataModelCardTitle'; import { SettingsDataModelFieldPreviewCard } from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard'; +import { SettingsDataModelObjectSummary } from '@/settings/data-model/objects/components/SettingsDataModelObjectSummary'; import { SettingsDataModelObjectIdentifiersForm, SettingsDataModelObjectIdentifiersFormValues, } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectIdentifiersForm'; -import { SettingsDataModelObjectSummary } from '@/settings/data-model/objects/SettingsDataModelObjectSummary'; import { Card } from '@/ui/layout/card/components/Card'; import { CardContent } from '@/ui/layout/card/components/CardContent'; diff --git a/packages/twenty-front/src/modules/settings/developers/components/SettingsApiKeysTable.tsx b/packages/twenty-front/src/modules/settings/developers/components/SettingsApiKeysTable.tsx index 0d1a9fc12660..3b47bad471f0 100644 --- a/packages/twenty-front/src/modules/settings/developers/components/SettingsApiKeysTable.tsx +++ b/packages/twenty-front/src/modules/settings/developers/components/SettingsApiKeysTable.tsx @@ -3,7 +3,7 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { SettingsApiKeysFieldItemTableRow } from '@/settings/developers/components/SettingsApiKeysFieldItemTableRow'; import { ApiFieldItem } from '@/settings/developers/types/api-key/ApiFieldItem'; import { ApiKey } from '@/settings/developers/types/api-key/ApiKey'; -import { formatExpirations } from '@/settings/developers/utils/format-expiration'; +import { formatExpirations } from '@/settings/developers/utils/formatExpiration'; import { Table } from '@/ui/layout/table/components/Table'; import { TableBody } from '@/ui/layout/table/components/TableBody'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; diff --git a/packages/twenty-front/src/modules/settings/developers/utils/__tests__/compute-new-expiration-date.test.ts b/packages/twenty-front/src/modules/settings/developers/utils/__tests__/computeNewExpirationDate.test.ts similarity index 96% rename from packages/twenty-front/src/modules/settings/developers/utils/__tests__/compute-new-expiration-date.test.ts rename to packages/twenty-front/src/modules/settings/developers/utils/__tests__/computeNewExpirationDate.test.ts index bd2a1db5bf7f..fa8d566e0cc2 100644 --- a/packages/twenty-front/src/modules/settings/developers/utils/__tests__/compute-new-expiration-date.test.ts +++ b/packages/twenty-front/src/modules/settings/developers/utils/__tests__/computeNewExpirationDate.test.ts @@ -1,4 +1,4 @@ -import { computeNewExpirationDate } from '@/settings/developers/utils/compute-new-expiration-date'; +import { computeNewExpirationDate } from '@/settings/developers/utils/computeNewExpirationDate'; jest.useFakeTimers().setSystemTime(new Date('2024-01-01T00:00:00.000Z')); diff --git a/packages/twenty-front/src/modules/settings/developers/utils/__tests__/format-expiration.test.ts b/packages/twenty-front/src/modules/settings/developers/utils/__tests__/formatExpiration.test.ts similarity index 99% rename from packages/twenty-front/src/modules/settings/developers/utils/__tests__/format-expiration.test.ts rename to packages/twenty-front/src/modules/settings/developers/utils/__tests__/formatExpiration.test.ts index c993984b0579..68731a78ce6d 100644 --- a/packages/twenty-front/src/modules/settings/developers/utils/__tests__/format-expiration.test.ts +++ b/packages/twenty-front/src/modules/settings/developers/utils/__tests__/formatExpiration.test.ts @@ -1,4 +1,4 @@ -import { formatExpiration } from '@/settings/developers/utils/format-expiration'; +import { formatExpiration } from '@/settings/developers/utils/formatExpiration'; jest.useFakeTimers().setSystemTime(new Date('2024-01-01T00:00:00.000Z')); diff --git a/packages/twenty-front/src/modules/settings/developers/utils/compute-new-expiration-date.ts b/packages/twenty-front/src/modules/settings/developers/utils/computeNewExpirationDate.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/developers/utils/compute-new-expiration-date.ts rename to packages/twenty-front/src/modules/settings/developers/utils/computeNewExpirationDate.ts diff --git a/packages/twenty-front/src/modules/settings/developers/utils/format-expiration.ts b/packages/twenty-front/src/modules/settings/developers/utils/formatExpiration.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/developers/utils/format-expiration.ts rename to packages/twenty-front/src/modules/settings/developers/utils/formatExpiration.ts diff --git a/packages/twenty-front/src/modules/settings/hooks/useExpandedHeightAnimation.tsx b/packages/twenty-front/src/modules/settings/hooks/useExpandedHeightAnimation.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/hooks/useExpandedHeightAnimation.tsx rename to packages/twenty-front/src/modules/settings/hooks/useExpandedHeightAnimation.ts diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockPage.tsx b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockPage.tsx index 2b17a655549d..9b36b1541abd 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockPage.tsx +++ b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockPage.tsx @@ -3,11 +3,11 @@ import { IconBuildingSkyscraper } from 'twenty-ui'; import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { SignInBackgroundMockContainer } from '@/sign-in-background-mock/components/SignInBackgroundMockContainer'; -import { PageAddButton } from '@/ui/layout/page/PageAddButton'; -import { PageBody } from '@/ui/layout/page/PageBody'; -import { PageContainer } from '@/ui/layout/page/PageContainer'; -import { PageHeader } from '@/ui/layout/page/PageHeader'; -import { PageHotkeysEffect } from '@/ui/layout/page/PageHotkeysEffect'; +import { PageAddButton } from '@/ui/layout/page/components/PageAddButton'; +import { PageBody } from '@/ui/layout/page/components/PageBody'; +import { PageContainer } from '@/ui/layout/page/components/PageContainer'; +import { PageHeader } from '@/ui/layout/page/components/PageHeader'; +import { PageHotkeysEffect } from '@/ui/layout/page/components/PageHotkeysEffect'; const StyledTableContainer = styled.div` display: flex; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/tests/mockRsiValues.ts b/packages/twenty-front/src/modules/spreadsheet-import/__mocks__/mockRsiValues.ts similarity index 100% rename from packages/twenty-front/src/modules/spreadsheet-import/tests/mockRsiValues.ts rename to packages/twenty-front/src/modules/spreadsheet-import/__mocks__/mockRsiValues.ts diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/MatchColumns.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/MatchColumns.stories.tsx index 47cb4e54d0b8..ac1a4da5acb8 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/MatchColumns.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/MatchColumns.stories.tsx @@ -1,10 +1,10 @@ import { Meta } from '@storybook/react'; +import { mockRsiValues } from '@/spreadsheet-import/__mocks__/mockRsiValues'; import { ModalWrapper } from '@/spreadsheet-import/components/ModalWrapper'; import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/components/ReactSpreadsheetImportContextProvider'; import { MatchColumnsStep } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep'; import { SpreadsheetImportStep } from '@/spreadsheet-import/steps/types/SpreadsheetImportStep'; -import { mockRsiValues } from '@/spreadsheet-import/tests/mockRsiValues'; import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectHeader.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectHeader.stories.tsx index a87f0ce4226c..ad33171faa3f 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectHeader.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectHeader.stories.tsx @@ -1,13 +1,13 @@ import { Meta } from '@storybook/react'; +import { + headerSelectionTableFields, + mockRsiValues, +} from '@/spreadsheet-import/__mocks__/mockRsiValues'; import { ModalWrapper } from '@/spreadsheet-import/components/ModalWrapper'; import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/components/ReactSpreadsheetImportContextProvider'; import { SelectHeaderStep } from '@/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep'; import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType'; -import { - headerSelectionTableFields, - mockRsiValues, -} from '@/spreadsheet-import/tests/mockRsiValues'; import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope'; const meta: Meta = { diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectSheet.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectSheet.stories.tsx index e48542f1a089..57b5162793cb 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectSheet.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectSheet.stories.tsx @@ -1,10 +1,10 @@ import { Meta } from '@storybook/react'; +import { mockRsiValues } from '@/spreadsheet-import/__mocks__/mockRsiValues'; import { ModalWrapper } from '@/spreadsheet-import/components/ModalWrapper'; import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/components/ReactSpreadsheetImportContextProvider'; import { SelectSheetStep } from '@/spreadsheet-import/steps/components/SelectSheetStep/SelectSheetStep'; import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType'; -import { mockRsiValues } from '@/spreadsheet-import/tests/mockRsiValues'; import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope'; const meta: Meta = { diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Upload.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Upload.stories.tsx index 7f2b295fb545..0757b7e619d4 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Upload.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Upload.stories.tsx @@ -1,10 +1,10 @@ import { Meta } from '@storybook/react'; +import { mockRsiValues } from '@/spreadsheet-import/__mocks__/mockRsiValues'; import { ModalWrapper } from '@/spreadsheet-import/components/ModalWrapper'; import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/components/ReactSpreadsheetImportContextProvider'; import { UploadStep } from '@/spreadsheet-import/steps/components/UploadStep/UploadStep'; import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType'; -import { mockRsiValues } from '@/spreadsheet-import/tests/mockRsiValues'; import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Validation.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Validation.stories.tsx index 9126371d1dc2..58894c817ce0 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Validation.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Validation.stories.tsx @@ -1,13 +1,13 @@ import { Meta } from '@storybook/react'; -import { ModalWrapper } from '@/spreadsheet-import/components/ModalWrapper'; -import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/components/ReactSpreadsheetImportContextProvider'; -import { ValidationStep } from '@/spreadsheet-import/steps/components/ValidationStep/ValidationStep'; import { editableTableInitialData, importedColums, mockRsiValues, -} from '@/spreadsheet-import/tests/mockRsiValues'; +} from '@/spreadsheet-import/__mocks__/mockRsiValues'; +import { ModalWrapper } from '@/spreadsheet-import/components/ModalWrapper'; +import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/components/ReactSpreadsheetImportContextProvider'; +import { ValidationStep } from '@/spreadsheet-import/steps/components/ValidationStep/ValidationStep'; import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope'; const meta: Meta = { diff --git a/packages/twenty-front/src/modules/ui/input/code-editor/components/CodeEditor.tsx b/packages/twenty-front/src/modules/ui/input/code-editor/components/CodeEditor.tsx index 1240a6d6025e..723b04a9f69b 100644 --- a/packages/twenty-front/src/modules/ui/input/code-editor/components/CodeEditor.tsx +++ b/packages/twenty-front/src/modules/ui/input/code-editor/components/CodeEditor.tsx @@ -1,11 +1,11 @@ -import Editor, { Monaco, EditorProps } from '@monaco-editor/react'; -import dotenv from 'dotenv'; -import { AutoTypings } from 'monaco-editor-auto-typings'; -import { editor, MarkerSeverity } from 'monaco-editor'; -import { codeEditorTheme } from '@/ui/input/code-editor/theme/CodeEditorTheme'; +import { useGetAvailablePackages } from '@/settings/serverless-functions/hooks/useGetAvailablePackages'; +import { codeEditorTheme } from '@/ui/input/code-editor/utils/codeEditorTheme'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { useGetAvailablePackages } from '@/settings/serverless-functions/hooks/useGetAvailablePackages'; +import Editor, { EditorProps, Monaco } from '@monaco-editor/react'; +import dotenv from 'dotenv'; +import { MarkerSeverity, editor } from 'monaco-editor'; +import { AutoTypings } from 'monaco-editor-auto-typings'; import { isDefined } from '~/utils/isDefined'; const StyledEditor = styled(Editor)` diff --git a/packages/twenty-front/src/modules/ui/input/code-editor/theme/CodeEditorTheme.ts b/packages/twenty-front/src/modules/ui/input/code-editor/utils/codeEditorTheme.ts similarity index 100% rename from packages/twenty-front/src/modules/ui/input/code-editor/theme/CodeEditorTheme.ts rename to packages/twenty-front/src/modules/ui/input/code-editor/utils/codeEditorTheme.ts diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx index e7a330c81ff3..ebca2067fcdc 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx @@ -17,7 +17,7 @@ import { UserContext } from '@/users/contexts/UserContext'; import { VariableDateViewFilterValueDirection, VariableDateViewFilterValueUnit, -} from '@/views/utils/view-filter-value/resolveDateViewFilterValue'; +} from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; import { useContext } from 'react'; import 'react-datepicker/dist/react-datepicker.css'; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx index 0a9328577dba..d970f3c825b1 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx @@ -1,12 +1,13 @@ -import { RELATIVE_DATE_DIRECTION_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateDirectionSelectOptions'; -import { RELATIVE_DATE_UNITS_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions'; import { Select } from '@/ui/input/components/Select'; import { TextInput } from '@/ui/input/components/TextInput'; +import { RELATIVE_DATE_DIRECTION_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateDirectionSelectOptions'; +import { RELATIVE_DATE_UNITS_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions'; import { VariableDateViewFilterValueDirection, - variableDateViewFilterValuePartsSchema, VariableDateViewFilterValueUnit, -} from '@/views/utils/view-filter-value/resolveDateViewFilterValue'; + variableDateViewFilterValuePartsSchema, +} from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; + import styled from '@emotion/styled'; import { useEffect, useState } from 'react'; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/constants/RelativeDateDirectionSelectOptions.ts b/packages/twenty-front/src/modules/ui/input/components/internal/date/constants/RelativeDateDirectionSelectOptions.ts index d13926719f0f..3a066f722d86 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/constants/RelativeDateDirectionSelectOptions.ts +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/constants/RelativeDateDirectionSelectOptions.ts @@ -1,4 +1,4 @@ -import { VariableDateViewFilterValueDirection } from '@/views/utils/view-filter-value/resolveDateViewFilterValue'; +import { VariableDateViewFilterValueDirection } from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; type RelativeDateDirectionOption = { value: VariableDateViewFilterValueDirection; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions.ts b/packages/twenty-front/src/modules/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions.ts index bf65953f63bc..832fc41f7cad 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions.ts +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions.ts @@ -1,4 +1,4 @@ -import { VariableDateViewFilterValueUnit } from '@/views/utils/view-filter-value/resolveDateViewFilterValue'; +import { VariableDateViewFilterValueUnit } from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; type RelativeDateUnit = { value: VariableDateViewFilterValueUnit; diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx index f2a940de52bd..63af03fb0d32 100644 --- a/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx +++ b/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx @@ -5,8 +5,8 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { ClipboardEvent } from 'react'; -import { blockSchema } from '@/activities/blocks/schema'; -import { getSlashMenu } from '@/activities/blocks/slashMenu'; +import { BLOCK_SCHEMA } from '@/activities/blocks/constants/Schema'; +import { getSlashMenu } from '@/activities/blocks/utils/getSlashMenu'; import { CustomSideMenu } from '@/ui/input/editor/components/CustomSideMenu'; import { CustomSlashMenu, @@ -14,7 +14,7 @@ import { } from '@/ui/input/editor/components/CustomSlashMenu'; interface BlockEditorProps { - editor: typeof blockSchema.BlockNoteEditor; + editor: typeof BLOCK_SCHEMA.BlockNoteEditor; onFocus?: () => void; onBlur?: () => void; onPaste?: (event: ClipboardEvent) => void; diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/CustomAddBlockItem.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/CustomAddBlockItem.tsx index 2eeb9862173e..02076198daed 100644 --- a/packages/twenty-front/src/modules/ui/input/editor/components/CustomAddBlockItem.tsx +++ b/packages/twenty-front/src/modules/ui/input/editor/components/CustomAddBlockItem.tsx @@ -1,9 +1,9 @@ -import { blockSchema } from '@/activities/blocks/schema'; +import { BLOCK_SCHEMA } from '@/activities/blocks/constants/Schema'; import { useComponentsContext } from '@blocknote/react'; type CustomAddBlockItemProps = { - editor: typeof blockSchema.BlockNoteEditor; + editor: typeof BLOCK_SCHEMA.BlockNoteEditor; children: React.ReactNode; // Adding the children prop }; diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenu.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenu.tsx index 6f44e0ebc501..62a6443ceab9 100644 --- a/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenu.tsx +++ b/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenu.tsx @@ -1,4 +1,4 @@ -import { blockSchema } from '@/activities/blocks/schema'; +import { BLOCK_SCHEMA } from '@/activities/blocks/constants/Schema'; import { CustomAddBlockItem } from '@/ui/input/editor/components/CustomAddBlockItem'; import { CustomSideMenuOptions } from '@/ui/input/editor/components/CustomSideMenuOptions'; import { @@ -13,7 +13,7 @@ import styled from '@emotion/styled'; import { IconColorSwatch, IconPlus, IconTrash } from 'twenty-ui'; type CustomSideMenuProps = { - editor: typeof blockSchema.BlockNoteEditor; + editor: typeof BLOCK_SCHEMA.BlockNoteEditor; }; const StyledDivToCreateGap = styled.div` diff --git a/packages/twenty-front/src/modules/ui/input/editor/utils/__tests__/getFirstNonEmptyLineOfRichText.test.tsx b/packages/twenty-front/src/modules/ui/input/editor/utils/__tests__/getFirstNonEmptyLineOfRichText.test.ts similarity index 100% rename from packages/twenty-front/src/modules/ui/input/editor/utils/__tests__/getFirstNonEmptyLineOfRichText.test.tsx rename to packages/twenty-front/src/modules/ui/input/editor/utils/__tests__/getFirstNonEmptyLineOfRichText.test.ts diff --git a/packages/twenty-front/src/modules/ui/layout/draggable-list/__stories__/DraggableItem.stories.tsx b/packages/twenty-front/src/modules/ui/layout/draggable-list/components/__stories__/DraggableItem.stories.tsx similarity index 92% rename from packages/twenty-front/src/modules/ui/layout/draggable-list/__stories__/DraggableItem.stories.tsx rename to packages/twenty-front/src/modules/ui/layout/draggable-list/components/__stories__/DraggableItem.stories.tsx index a6b2cffc0e03..810be399c972 100644 --- a/packages/twenty-front/src/modules/ui/layout/draggable-list/__stories__/DraggableItem.stories.tsx +++ b/packages/twenty-front/src/modules/ui/layout/draggable-list/components/__stories__/DraggableItem.stories.tsx @@ -2,10 +2,9 @@ import { DragDropContext, Droppable } from '@hello-pangea/dnd'; import { Meta, StoryObj } from '@storybook/react'; import { ComponentDecorator, IconBell } from 'twenty-ui'; +import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem'; import { MenuItemDraggable } from '@/ui/navigation/menu-item/components/MenuItemDraggable'; -import { DraggableItem } from '../components/DraggableItem'; - const meta: Meta = { title: 'UI/Layout/DraggableList/DraggableItem', component: DraggableItem, diff --git a/packages/twenty-front/src/modules/ui/layout/draggable-list/__stories__/DraggableList.stories.tsx b/packages/twenty-front/src/modules/ui/layout/draggable-list/components/__stories__/DraggableList.stories.tsx similarity index 89% rename from packages/twenty-front/src/modules/ui/layout/draggable-list/__stories__/DraggableList.stories.tsx rename to packages/twenty-front/src/modules/ui/layout/draggable-list/components/__stories__/DraggableList.stories.tsx index 071d8a336bac..813481958f54 100644 --- a/packages/twenty-front/src/modules/ui/layout/draggable-list/__stories__/DraggableList.stories.tsx +++ b/packages/twenty-front/src/modules/ui/layout/draggable-list/components/__stories__/DraggableList.stories.tsx @@ -2,11 +2,10 @@ import { action } from '@storybook/addon-actions'; import { Meta, StoryObj } from '@storybook/react'; import { ComponentDecorator, IconBell } from 'twenty-ui'; +import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem'; +import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList'; import { MenuItemDraggable } from '@/ui/navigation/menu-item/components/MenuItemDraggable'; -import { DraggableItem } from '../components/DraggableItem'; -import { DraggableList } from '../components/DraggableList'; - const meta: Meta = { title: 'UI/Layout/DraggableList/DraggableList', component: DraggableList, diff --git a/packages/twenty-front/src/modules/ui/layout/page/BlankLayout.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/BlankLayout.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/BlankLayout.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/BlankLayout.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/DefaultLayout.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/DefaultLayout.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/PageAddButton.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageAddButton.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/PageAddButton.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/PageAddButton.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/PageBody.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageBody.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/PageBody.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/PageBody.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/PageContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageContainer.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/PageContainer.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/PageContainer.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/PageFavoriteButton.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageFavoriteButton.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/PageFavoriteButton.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/PageFavoriteButton.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/PageHotkeysEffect.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageHotkeysEffect.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/PageHotkeysEffect.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/PageHotkeysEffect.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/PagePanel.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PagePanel.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/PagePanel.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/PagePanel.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/RightDrawerContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/RightDrawerContainer.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/RightDrawerContainer.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/RightDrawerContainer.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/ShowPageContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/ShowPageContainer.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/page/SubMenuTopBarContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/page/SubMenuTopBarContainer.tsx rename to packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx index d8bf449d6afd..3365a170e2a6 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx @@ -3,7 +3,7 @@ import { EmailThreads } from '@/activities/emails/components/EmailThreads'; import { Attachments } from '@/activities/files/components/Attachments'; import { Notes } from '@/activities/notes/components/Notes'; import { ObjectTasks } from '@/activities/tasks/components/ObjectTasks'; -import { TimelineActivities } from '@/activities/timelineActivities/components/TimelineActivities'; +import { TimelineActivities } from '@/activities/timeline-activities/components/TimelineActivities'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; diff --git a/packages/twenty-front/src/modules/ui/layout/top-bar/TopBar.tsx b/packages/twenty-front/src/modules/ui/layout/top-bar/components/TopBar.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/top-bar/TopBar.tsx rename to packages/twenty-front/src/modules/ui/layout/top-bar/components/TopBar.tsx diff --git a/packages/twenty-front/src/modules/ui/utilities/page-title/PageTitle.tsx b/packages/twenty-front/src/modules/ui/utilities/page-title/components/PageTitle.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/utilities/page-title/PageTitle.tsx rename to packages/twenty-front/src/modules/ui/utilities/page-title/components/PageTitle.tsx diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/__tests__/useAvailableScopeId.test.tsx b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/__tests__/useAvailableScopeId.test.tsx index afb281b9a759..05a638e71727 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/__tests__/useAvailableScopeId.test.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/__tests__/useAvailableScopeId.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { renderHook } from '@testing-library/react'; +import React from 'react'; import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts index abf1b33900b4..02d447a7fd32 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts @@ -1,6 +1,5 @@ -import { Context, createContext } from 'react'; - import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; +import { Context, createContext } from 'react'; type ScopeInternalContext = Context; diff --git a/packages/twenty-front/src/modules/ui/utilities/responsive/hooks/__tests__/isMobile.test.tsx b/packages/twenty-front/src/modules/ui/utilities/responsive/hooks/__tests__/useIsMobile.test.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/utilities/responsive/hooks/__tests__/isMobile.test.tsx rename to packages/twenty-front/src/modules/ui/utilities/responsive/hooks/__tests__/useIsMobile.test.tsx diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2_alpha.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2Alpha.ts similarity index 100% rename from packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2_alpha.ts rename to packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2Alpha.ts diff --git a/packages/twenty-front/src/modules/views/components/ViewBar.tsx b/packages/twenty-front/src/modules/views/components/ViewBar.tsx index 186f54b691ba..59642d58a301 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBar.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBar.tsx @@ -5,7 +5,7 @@ import { ObjectFilterDropdownButton } from '@/object-record/object-filter-dropdo import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope'; import { ObjectSortDropdownButton } from '@/object-record/object-sort-dropdown/components/ObjectSortDropdownButton'; import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; -import { TopBar } from '@/ui/layout/top-bar/TopBar'; +import { TopBar } from '@/ui/layout/top-bar/components/TopBar'; import { QueryParamsFiltersEffect } from '@/views/components/QueryParamsFiltersEffect'; import { QueryParamsViewIdEffect } from '@/views/components/QueryParamsViewIdEffect'; import { ViewBarEffect } from '@/views/components/ViewBarEffect'; diff --git a/packages/twenty-front/src/modules/views/components/ViewBarPageTitle.tsx b/packages/twenty-front/src/modules/views/components/ViewBarPageTitle.tsx index c7ab13c549b5..758a83b733be 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarPageTitle.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarPageTitle.tsx @@ -1,6 +1,6 @@ import { useParams } from 'react-router-dom'; -import { PageTitle } from '@/ui/utilities/page-title/PageTitle'; +import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { capitalize } from '~/utils/string/capitalize'; diff --git a/packages/twenty-front/src/modules/views/hooks/internal/usePersistViewFieldRecords.ts b/packages/twenty-front/src/modules/views/hooks/internal/usePersistViewFieldRecords.ts index 15327a303579..fce290183f7c 100644 --- a/packages/twenty-front/src/modules/views/hooks/internal/usePersistViewFieldRecords.ts +++ b/packages/twenty-front/src/modules/views/hooks/internal/usePersistViewFieldRecords.ts @@ -1,5 +1,5 @@ -import { useCallback } from 'react'; import { useApolloClient } from '@apollo/client'; +import { useCallback } from 'react'; import { v4 } from 'uuid'; import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; diff --git a/packages/twenty-front/src/modules/views/utils/view-filter-value/computeVariableDateViewFilterValue.ts b/packages/twenty-front/src/modules/views/view-filter-value/utils/computeVariableDateViewFilterValue.ts similarity index 83% rename from packages/twenty-front/src/modules/views/utils/view-filter-value/computeVariableDateViewFilterValue.ts rename to packages/twenty-front/src/modules/views/view-filter-value/utils/computeVariableDateViewFilterValue.ts index 1b09bc91348b..d34e4b7f1b35 100644 --- a/packages/twenty-front/src/modules/views/utils/view-filter-value/computeVariableDateViewFilterValue.ts +++ b/packages/twenty-front/src/modules/views/view-filter-value/utils/computeVariableDateViewFilterValue.ts @@ -1,7 +1,7 @@ import { VariableDateViewFilterValueDirection, VariableDateViewFilterValueUnit, -} from '@/views/utils/view-filter-value/resolveDateViewFilterValue'; +} from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; export const computeVariableDateViewFilterValue = ( direction: VariableDateViewFilterValueDirection, diff --git a/packages/twenty-front/src/modules/views/utils/view-filter-value/resolveDateViewFilterValue.ts b/packages/twenty-front/src/modules/views/view-filter-value/utils/resolveDateViewFilterValue.ts similarity index 100% rename from packages/twenty-front/src/modules/views/utils/view-filter-value/resolveDateViewFilterValue.ts rename to packages/twenty-front/src/modules/views/view-filter-value/utils/resolveDateViewFilterValue.ts diff --git a/packages/twenty-front/src/modules/views/utils/view-filter-value/resolveFilterValue.ts b/packages/twenty-front/src/modules/views/view-filter-value/utils/resolveFilterValue.ts similarity index 91% rename from packages/twenty-front/src/modules/views/utils/view-filter-value/resolveFilterValue.ts rename to packages/twenty-front/src/modules/views/view-filter-value/utils/resolveFilterValue.ts index 34afbb46ad1a..c5c4e064507b 100644 --- a/packages/twenty-front/src/modules/views/utils/view-filter-value/resolveFilterValue.ts +++ b/packages/twenty-front/src/modules/views/view-filter-value/utils/resolveFilterValue.ts @@ -1,7 +1,7 @@ import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { FilterableFieldType } from '@/object-record/object-filter-dropdown/types/FilterableFieldType'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; -import { resolveNumberViewFilterValue } from '@/views/utils/view-filter-value/resolveNumberViewFilterValue'; +import { resolveNumberViewFilterValue } from '@/views/view-filter-value/utils/resolveNumberViewFilterValue'; import { resolveDateViewFilterValue, ResolvedDateViewFilterValue, diff --git a/packages/twenty-front/src/modules/views/utils/view-filter-value/resolveNumberViewFilterValue.ts b/packages/twenty-front/src/modules/views/view-filter-value/utils/resolveNumberViewFilterValue.ts similarity index 100% rename from packages/twenty-front/src/modules/views/utils/view-filter-value/resolveNumberViewFilterValue.ts rename to packages/twenty-front/src/modules/views/view-filter-value/utils/resolveNumberViewFilterValue.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useActivateWorkflowVersion.tsx b/packages/twenty-front/src/modules/workflow/hooks/useActivateWorkflowVersion.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useActivateWorkflowVersion.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useActivateWorkflowVersion.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useCreateNewWorkflowVersion.tsx b/packages/twenty-front/src/modules/workflow/hooks/useCreateNewWorkflowVersion.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useCreateNewWorkflowVersion.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useCreateNewWorkflowVersion.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useCreateStep.tsx b/packages/twenty-front/src/modules/workflow/hooks/useCreateStep.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useCreateStep.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useCreateStep.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useDeactivateWorkflowVersion.tsx b/packages/twenty-front/src/modules/workflow/hooks/useDeactivateWorkflowVersion.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useDeactivateWorkflowVersion.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useDeactivateWorkflowVersion.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useDeleteOneStep.tsx b/packages/twenty-front/src/modules/workflow/hooks/useDeleteOneStep.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useDeleteOneStep.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useDeleteOneStep.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useDeleteOneWorkflowVersion.tsx b/packages/twenty-front/src/modules/workflow/hooks/useDeleteOneWorkflowVersion.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useDeleteOneWorkflowVersion.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useDeleteOneWorkflowVersion.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useStartNodeCreation.tsx b/packages/twenty-front/src/modules/workflow/hooks/useStartNodeCreation.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useStartNodeCreation.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useStartNodeCreation.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useTriggerNodeSelection.tsx b/packages/twenty-front/src/modules/workflow/hooks/useTriggerNodeSelection.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useTriggerNodeSelection.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useTriggerNodeSelection.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useUpdateWorkflowVersionStep.tsx b/packages/twenty-front/src/modules/workflow/hooks/useUpdateWorkflowVersionStep.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useUpdateWorkflowVersionStep.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useUpdateWorkflowVersionStep.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useUpdateWorkflowVersionTrigger.tsx b/packages/twenty-front/src/modules/workflow/hooks/useUpdateWorkflowVersionTrigger.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useUpdateWorkflowVersionTrigger.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useUpdateWorkflowVersionTrigger.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersion.tsx b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersion.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersion.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersion.ts diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.tsx b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.tsx rename to packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts diff --git a/packages/twenty-front/src/modules/workflow/utils/assertWorkflowWithCurrentVersionIsDefined.tsx b/packages/twenty-front/src/modules/workflow/utils/assertWorkflowWithCurrentVersionIsDefined.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/utils/assertWorkflowWithCurrentVersionIsDefined.tsx rename to packages/twenty-front/src/modules/workflow/utils/assertWorkflowWithCurrentVersionIsDefined.ts diff --git a/packages/twenty-front/src/modules/workspace-member/grapqhql/fragments/workspaceMemberQueryFragment.ts b/packages/twenty-front/src/modules/workspace-member/graphql/fragments/workspaceMemberQueryFragment.ts similarity index 100% rename from packages/twenty-front/src/modules/workspace-member/grapqhql/fragments/workspaceMemberQueryFragment.ts rename to packages/twenty-front/src/modules/workspace-member/graphql/fragments/workspaceMemberQueryFragment.ts diff --git a/packages/twenty-front/src/modules/workspace-member/grapqhql/mutations/addUserToWorkspace.ts b/packages/twenty-front/src/modules/workspace-member/graphql/mutations/addUserToWorkspace.ts similarity index 100% rename from packages/twenty-front/src/modules/workspace-member/grapqhql/mutations/addUserToWorkspace.ts rename to packages/twenty-front/src/modules/workspace-member/graphql/mutations/addUserToWorkspace.ts diff --git a/packages/twenty-front/src/modules/workspace-member/grapqhql/mutations/addUserToWorkspaceByInviteToken.ts b/packages/twenty-front/src/modules/workspace-member/graphql/mutations/addUserToWorkspaceByInviteToken.ts similarity index 100% rename from packages/twenty-front/src/modules/workspace-member/grapqhql/mutations/addUserToWorkspaceByInviteToken.ts rename to packages/twenty-front/src/modules/workspace-member/graphql/mutations/addUserToWorkspaceByInviteToken.ts diff --git a/packages/twenty-front/src/pages/not-found/NotFound.tsx b/packages/twenty-front/src/pages/not-found/NotFound.tsx index bf3acc27aed8..4270c5718b4b 100644 --- a/packages/twenty-front/src/pages/not-found/NotFound.tsx +++ b/packages/twenty-front/src/pages/not-found/NotFound.tsx @@ -11,7 +11,7 @@ import { AnimatedPlaceholderErrorTitle, } from '@/ui/layout/animated-placeholder/components/ErrorPlaceholderStyled'; import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink'; -import { PageTitle } from '@/ui/utilities/page-title/PageTitle'; +import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; const StyledBackDrop = styled.div` align-items: center; diff --git a/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx b/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx index 44eb6f203b25..dfefa674cdf1 100644 --- a/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx @@ -9,9 +9,9 @@ import { RecordIndexPageHeader } from '@/object-record/record-index/components/R import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick'; import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords'; -import { PageBody } from '@/ui/layout/page/PageBody'; -import { PageContainer } from '@/ui/layout/page/PageContainer'; -import { PageTitle } from '@/ui/utilities/page-title/PageTitle'; +import { PageBody } from '@/ui/layout/page/components/PageBody'; +import { PageContainer } from '@/ui/layout/page/components/PageContainer'; +import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; import { useRecoilCallback } from 'recoil'; import { capitalize } from '~/utils/string/capitalize'; diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx index 0ecb2cb569de..6c838400370e 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx @@ -1,14 +1,14 @@ import { useParams } from 'react-router-dom'; -import { TimelineActivityContext } from '@/activities/timelineActivities/contexts/TimelineActivityContext'; +import { TimelineActivityContext } from '@/activities/timeline-activities/contexts/TimelineActivityContext'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer'; import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage'; import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect'; import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; -import { PageBody } from '@/ui/layout/page/PageBody'; -import { PageContainer } from '@/ui/layout/page/PageContainer'; -import { PageTitle } from '@/ui/utilities/page-title/PageTitle'; +import { PageBody } from '@/ui/layout/page/components/PageBody'; +import { PageContainer } from '@/ui/layout/page/components/PageContainer'; +import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; import { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader'; import { RecordShowPageWorkflowVersionHeader } from '@/workflow/components/RecordShowPageWorkflowVersionHeader'; import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader'; diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPageBaseHeader.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPageBaseHeader.tsx index a7577114c092..eb64af722938 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPageBaseHeader.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPageBaseHeader.tsx @@ -1,6 +1,6 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { PageFavoriteButton } from '@/ui/layout/page/PageFavoriteButton'; +import { PageFavoriteButton } from '@/ui/layout/page/components/PageFavoriteButton'; import { ShowPageAddButton } from '@/ui/layout/show-page/components/ShowPageAddButton'; import { ShowPageMoreButton } from '@/ui/layout/show-page/components/ShowPageMoreButton'; diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPageHeader.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPageHeader.tsx index 7f91f3001055..9808158ec885 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPageHeader.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPageHeader.tsx @@ -1,6 +1,6 @@ import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage'; import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination'; -import { PageHeader } from '@/ui/layout/page/PageHeader'; +import { PageHeader } from '@/ui/layout/page/components/PageHeader'; export const RecordShowPageHeader = ({ objectNameSingular, diff --git a/packages/twenty-front/src/pages/settings/Releases.tsx b/packages/twenty-front/src/pages/settings/Releases.tsx index 3429ac9893ac..9e20f9c9557f 100644 --- a/packages/twenty-front/src/pages/settings/Releases.tsx +++ b/packages/twenty-front/src/pages/settings/Releases.tsx @@ -9,7 +9,7 @@ import { visit } from 'unist-util-visit'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; type ReleaseNote = { diff --git a/packages/twenty-front/src/pages/settings/SettingsBilling.tsx b/packages/twenty-front/src/pages/settings/SettingsBilling.tsx index 5a8c90a81a31..c1f3f4aa51a0 100644 --- a/packages/twenty-front/src/pages/settings/SettingsBilling.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsBilling.tsx @@ -19,7 +19,7 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { Button } from '@/ui/input/button/components/Button'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; import { diff --git a/packages/twenty-front/src/pages/settings/SettingsProfile.tsx b/packages/twenty-front/src/pages/settings/SettingsProfile.tsx index 0ff302645941..9e28b161164b 100644 --- a/packages/twenty-front/src/pages/settings/SettingsProfile.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsProfile.tsx @@ -8,7 +8,7 @@ import { NameFields } from '@/settings/profile/components/NameFields'; import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; export const SettingsProfile = () => ( diff --git a/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx b/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx index 329c736f1834..f61342a4c586 100644 --- a/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx @@ -7,7 +7,7 @@ import { NameField } from '@/settings/workspace/components/NameField'; import { ToggleImpersonate } from '@/settings/workspace/components/ToggleImpersonate'; import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { GithubVersionLink } from '@/ui/navigation/link/components/GithubVersionLink'; diff --git a/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx b/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx index 3ba11b7f22fb..033f103a9ff9 100644 --- a/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx @@ -25,7 +25,7 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { IconButton } from '@/ui/input/button/components/IconButton'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { Table } from '@/ui/layout/table/components/Table'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx index 5ff43e83219d..a827cd4a2533 100644 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx @@ -14,7 +14,7 @@ import { SettingsAccountsSettingsSection } from '@/settings/accounts/components/ import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; export const SettingsAccounts = () => { diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx index 2dc86e72e114..9e75f3297d15 100644 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx @@ -2,7 +2,7 @@ import { SettingsAccountsCalendarChannelsContainer } from '@/settings/accounts/c import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; export const SettingsAccountsCalendars = () => { diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx index 4e5732ef81b4..4cc777a62396 100644 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx @@ -2,7 +2,7 @@ import { SettingsAccountsMessageChannelsContainer } from '@/settings/accounts/co import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; export const SettingsAccountsEmails = () => ( diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsNewAccount.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsNewAccount.tsx index 35e90d9b2cf0..d46f4b99c7c7 100644 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsNewAccount.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/SettingsNewAccount.tsx @@ -2,7 +2,7 @@ import { SettingsNewAccountSection } from '@/settings/accounts/components/Settin import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; export const SettingsNewAccount = () => { return ( diff --git a/packages/twenty-front/src/pages/settings/crm-migration/SettingsCRMMigration.tsx b/packages/twenty-front/src/pages/settings/crm-migration/SettingsCRMMigration.tsx index 4c4dbc807c64..36c6c7b9abb8 100644 --- a/packages/twenty-front/src/pages/settings/crm-migration/SettingsCRMMigration.tsx +++ b/packages/twenty-front/src/pages/settings/crm-migration/SettingsCRMMigration.tsx @@ -7,7 +7,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { SettingsReadDocumentationButton } from '@/settings/developers/components/SettingsReadDocumentationButton'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { useRecoilValue } from 'recoil'; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx index 136bad77026b..6c368f0a0d47 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx @@ -17,7 +17,7 @@ import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; const newObjectFormSchema = settingsDataModelObjectAboutFormSchema; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPageContent.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPageContent.tsx index 37fb2d9c0cd2..d973ab8f3cd2 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPageContent.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPageContent.tsx @@ -5,7 +5,7 @@ import { SettingsObjectSummaryCard } from '@/settings/data-model/object-details/ import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { Button } from '@/ui/input/button/components/Button'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx index 3cbdfe3bdc7e..06cc4999feab 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx @@ -27,7 +27,7 @@ import { SettingsPath } from '@/types/SettingsPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { Button } from '@/ui/input/button/components/Button'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; const objectEditFormSchema = z diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx index 651243747a2e..a08d6658cff7 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx @@ -32,7 +32,7 @@ import { SettingsPath } from '@/types/SettingsPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { Button } from '@/ui/input/button/components/Button'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx index 5e8893813fb3..682cb7123de7 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx @@ -16,7 +16,7 @@ import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType import { AppPath } from '@/types/AppPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { View } from '@/views/types/View'; import { ViewType } from '@/views/types/ViewType'; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldSelect.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldSelect.tsx index cfc683510006..793279f38836 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldSelect.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldSelect.tsx @@ -6,7 +6,7 @@ import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/Set import { SettingsObjectNewFieldSelector } from '@/settings/data-model/fields/forms/components/SettingsObjectNewFieldSelector'; import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType'; import { AppPath } from '@/types/AppPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { zodResolver } from '@hookform/resolvers/zod'; import { useEffect } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectOverview.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectOverview.tsx index 215ae748bc99..e807ea134bf9 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectOverview.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectOverview.tsx @@ -3,7 +3,7 @@ import { ReactFlowProvider } from 'reactflow'; import { SettingsDataModelOverview } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverview'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; export const SettingsObjectOverview = () => { return ( diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjects.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjects.tsx index 7c7e280569d7..ba5fd0fd600b 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjects.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjects.tsx @@ -12,14 +12,14 @@ import { SettingsObjectMetadataItemTableRow, StyledObjectTableRow, } from '@/settings/data-model/object-details/components/SettingsObjectItemTableRow'; -import { SettingsObjectCoverImage } from '@/settings/data-model/objects/SettingsObjectCoverImage'; -import { SettingsObjectInactiveMenuDropDown } from '@/settings/data-model/objects/SettingsObjectInactiveMenuDropDown'; +import { SettingsObjectCoverImage } from '@/settings/data-model/objects/components/SettingsObjectCoverImage'; +import { SettingsObjectInactiveMenuDropDown } from '@/settings/data-model/objects/components/SettingsObjectInactiveMenuDropDown'; import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { Button } from '@/ui/input/button/components/Button'; import { TextInput } from '@/ui/input/components/TextInput'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { SortableTableHeader } from '@/ui/layout/table/components/SortableTableHeader'; import { Table } from '@/ui/layout/table/components/Table'; diff --git a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopers.tsx b/packages/twenty-front/src/pages/settings/developers/SettingsDevelopers.tsx index 35ce036694e1..a200a8445546 100644 --- a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopers.tsx +++ b/packages/twenty-front/src/pages/settings/developers/SettingsDevelopers.tsx @@ -9,7 +9,7 @@ import { SettingsWebhooksTable } from '@/settings/developers/components/Settings import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { Button } from '@/ui/input/button/components/Button'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; const StyledButtonContainer = styled.div` diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx index 7a9651b6893a..8d45c760cb59 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx @@ -15,8 +15,8 @@ import { ApiKeyInput } from '@/settings/developers/components/ApiKeyInput'; import { ApiKeyNameInput } from '@/settings/developers/components/ApiKeyNameInput'; import { apiKeyTokenState } from '@/settings/developers/states/generatedApiKeyTokenState'; import { ApiKey } from '@/settings/developers/types/api-key/ApiKey'; -import { computeNewExpirationDate } from '@/settings/developers/utils/compute-new-expiration-date'; -import { formatExpiration } from '@/settings/developers/utils/format-expiration'; +import { computeNewExpirationDate } from '@/settings/developers/utils/computeNewExpirationDate'; +import { formatExpiration } from '@/settings/developers/utils/formatExpiration'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; @@ -24,7 +24,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { Button } from '@/ui/input/button/components/Button'; import { TextInput } from '@/ui/input/components/TextInput'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { useGenerateApiKeyTokenMutation } from '~/generated/graphql'; diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx index 92951f0a5b43..93733b7cc64a 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx @@ -14,7 +14,7 @@ import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { Select } from '@/ui/input/components/Select'; import { TextInput } from '@/ui/input/components/TextInput'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { useSetRecoilState } from 'recoil'; import { Key } from 'ts-key-enum'; diff --git a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx index 006a4db6a88b..1a2316a0a317 100644 --- a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx @@ -21,7 +21,7 @@ import { Select } from '@/ui/input/components/Select'; import { TextArea } from '@/ui/input/components/TextArea'; import { TextInput } from '@/ui/input/components/TextInput'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useRecoilValue } from 'recoil'; diff --git a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhooksNew.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhooksNew.tsx index b473d3f28c76..4d0e7bb47abb 100644 --- a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhooksNew.tsx +++ b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhooksNew.tsx @@ -10,7 +10,7 @@ import { Webhook } from '@/settings/developers/types/webhook/Webhook'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { TextInput } from '@/ui/input/components/TextInput'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { isValidUrl } from '~/utils/url/isValidUrl'; diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationDatabase.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationDatabase.tsx index eb8ddd11f2cf..1b803f6355be 100644 --- a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationDatabase.tsx +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationDatabase.tsx @@ -11,7 +11,7 @@ import { useSettingsIntegrationCategories } from '@/settings/integrations/hooks/ import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { AppPath } from '@/types/AppPath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; export const SettingsIntegrationDatabase = () => { diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationEditDatabaseConnection.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationEditDatabaseConnection.tsx index 92de8008e048..10c57a8bcb4f 100644 --- a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationEditDatabaseConnection.tsx +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationEditDatabaseConnection.tsx @@ -2,7 +2,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { SettingsIntegrationEditDatabaseConnectionContainer } from '@/settings/integrations/database-connection/components/SettingsIntegrationEditDatabaseConnectionContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; export const SettingsIntegrationEditDatabaseConnection = () => { return ( diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection.tsx index e10f696446f6..017eeb5c279f 100644 --- a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection.tsx +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection.tsx @@ -21,7 +21,7 @@ import { AppPath } from '@/types/AppPath'; import { SettingsPath } from '@/types/SettingsPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { CreateRemoteServerInput } from '~/generated-metadata/graphql'; diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationShowDatabaseConnection.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationShowDatabaseConnection.tsx index 76f1aefa24c8..2d2000d536c3 100644 --- a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationShowDatabaseConnection.tsx +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationShowDatabaseConnection.tsx @@ -2,7 +2,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { SettingsIntegrationDatabaseConnectionShowContainer } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionShowContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; export const SettingsIntegrationShowDatabaseConnection = () => { return ( diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrations.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrations.tsx index bfd5db517c93..de44d7346c59 100644 --- a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrations.tsx +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrations.tsx @@ -3,7 +3,7 @@ import { SettingsIntegrationGroup } from '@/settings/integrations/components/Set import { useSettingsIntegrationCategories } from '@/settings/integrations/hooks/useSettingsIntegrationCategories'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; export const SettingsIntegrations = () => { const integrationCategories = useSettingsIntegrationCategories(); diff --git a/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsAppearance.tsx b/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsAppearance.tsx index 85ca252abfba..891d69d957ad 100644 --- a/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsAppearance.tsx +++ b/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsAppearance.tsx @@ -4,7 +4,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { ColorSchemePicker } from '@/ui/input/color-scheme/components/ColorSchemePicker'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { useColorScheme } from '@/ui/theme/hooks/useColorScheme'; import { DateTimeSettings } from '~/pages/settings/profile/appearance/components/DateTimeSettings'; diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionDetail.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionDetail.tsx index 2934066fd1a4..b6237754fdcc 100644 --- a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionDetail.tsx +++ b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionDetail.tsx @@ -14,7 +14,7 @@ import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { TabList } from '@/ui/layout/tab/components/TabList'; import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; @@ -23,8 +23,8 @@ import { useParams } from 'react-router-dom'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { IconCode, IconSettings, IconTestPipe } from 'twenty-ui'; import { usePreventOverlapCallback } from '~/hooks/usePreventOverlapCallback'; -import { isDefined } from '~/utils/isDefined'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; +import { isDefined } from '~/utils/isDefined'; const TAB_LIST_COMPONENT_ID = 'serverless-function-detail'; diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctions.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctions.tsx index 9cfd9b04ca42..1d240653c974 100644 --- a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctions.tsx +++ b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctions.tsx @@ -2,7 +2,7 @@ import { SettingsServerlessFunctionsTable } from '@/settings/serverless-function import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { Button } from '@/ui/input/button/components/Button'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink'; import { IconPlus } from 'twenty-ui'; diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx index 3e43717544ce..cb52a0c020df 100644 --- a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx +++ b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx @@ -1,6 +1,6 @@ import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { useNavigate } from 'react-router-dom'; import { SettingsServerlessFunctionNewForm } from '@/settings/serverless-functions/components/SettingsServerlessFunctionNewForm'; diff --git a/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx b/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx index c107d5466387..e47d8bcabac7 100644 --- a/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx @@ -1,7 +1,7 @@ import { Decorator } from '@storybook/react'; import { useMemo } from 'react'; -import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext'; import { getRecordChipGenerators } from '@/object-record/utils/getRecordChipGenerators'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; diff --git a/packages/twenty-front/src/testing/decorators/PageDecorator.tsx b/packages/twenty-front/src/testing/decorators/PageDecorator.tsx index 244772c809e6..7405490de3a9 100644 --- a/packages/twenty-front/src/testing/decorators/PageDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/PageDecorator.tsx @@ -14,9 +14,9 @@ import { RecoilRoot } from 'recoil'; import { ClientConfigProviderEffect } from '@/client-config/components/ClientConfigProviderEffect'; import { ApolloMetadataClientMockedProvider } from '@/object-metadata/hooks/__mocks__/ApolloMetadataClientMockedProvider'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { DefaultLayout } from '@/ui/layout/page/components/DefaultLayout'; import { UserProviderEffect } from '@/users/components/UserProviderEffect'; import { ClientConfigProvider } from '~/modules/client-config/components/ClientConfigProvider'; -import { DefaultLayout } from '~/modules/ui/layout/page/DefaultLayout'; import { UserProvider } from '~/modules/users/components/UserProvider'; import { mockedApolloClient } from '~/testing/mockedApolloClient'; diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index 971ab159737c..a716ba032f76 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -1,4 +1,4 @@ -import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; export const mockedTimelineActivities: Array = [ { diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts index 282f9d6dd202..a3a7af054b68 100644 --- a/packages/twenty-front/vite.config.ts +++ b/packages/twenty-front/vite.config.ts @@ -52,7 +52,7 @@ export default defineConfig(({ command, mode }) => { if (VITE_DISABLE_ESLINT_CHECKER !== 'true') { checkers['eslint'] = { lintCommand: - 'eslint . --report-unused-disable-directives --max-warnings 0 --config .eslintrc.cjs', + 'cd ../.. && eslint packages/twenty-front --report-unused-disable-directives --max-warnings 0 --config .eslintrc.cjs', }; } diff --git a/yarn.lock b/yarn.lock index 9d8eabefb6c3..475ba43b0b79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17097,6 +17097,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:8.10.0": + version: 8.10.0 + resolution: "@typescript-eslint/scope-manager@npm:8.10.0" + dependencies: + "@typescript-eslint/types": "npm:8.10.0" + "@typescript-eslint/visitor-keys": "npm:8.10.0" + checksum: 10c0/b8bb8635c4d6c00a3578d6265e3ee0f5d96d0c9dee534ed588aa411c3f4497fd71cce730c3ae7571e52453d955b191bc9edcc47c9af21a20c90e9a20f2371108 + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:6.21.0": version: 6.21.0 resolution: "@typescript-eslint/type-utils@npm:6.21.0" @@ -17152,6 +17162,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.10.0": + version: 8.10.0 + resolution: "@typescript-eslint/types@npm:8.10.0" + checksum: 10c0/f27dd43c8383e02e914a254257627e393dfc0f08b0f74a253c106813ae361f090271b2f3f2ef588fa3ca1329897d873da595bb5641fe8e3091b25eddca24b5d2 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/typescript-estree@npm:5.62.0" @@ -17208,6 +17225,25 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:8.10.0": + version: 8.10.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.10.0" + dependencies: + "@typescript-eslint/types": "npm:8.10.0" + "@typescript-eslint/visitor-keys": "npm:8.10.0" + debug: "npm:^4.3.4" + fast-glob: "npm:^3.3.2" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/535a740fe25be0e28fe68c41e3264273d1e5169c9f938e08cc0e3415c357726f43efa44621960108c318fc3305c425d29f3223b6e731d44d67f84058a8947304 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.45.0": version: 5.62.0 resolution: "@typescript-eslint/utils@npm:5.62.0" @@ -17257,6 +17293,20 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:^8.8.0": + version: 8.10.0 + resolution: "@typescript-eslint/utils@npm:8.10.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:8.10.0" + "@typescript-eslint/types": "npm:8.10.0" + "@typescript-eslint/typescript-estree": "npm:8.10.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + checksum: 10c0/a21a2933517176abd00fcd5d8d80023e35dc3d89d5746bbac43790b4e984ab1f371117db08048bce7f42d54c64f4e0e35161149f8f34fd25a27bff9d1110fd16 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" @@ -17287,6 +17337,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:8.10.0": + version: 8.10.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.10.0" + dependencies: + "@typescript-eslint/types": "npm:8.10.0" + eslint-visitor-keys: "npm:^3.4.3" + checksum: 10c0/14721c4ac939640d5fd1ee1b6eeb07604b11a6017e319e21dcc71e7aac2992341fc7ae1992d977bad4433b6a1d0d1c0c279e6927316b26245f6e333f922fa458 + languageName: node + linkType: hard + "@ungap/structured-clone@npm:^1.2.0": version: 1.2.0 resolution: "@ungap/structured-clone@npm:1.2.0" @@ -22284,6 +22344,19 @@ __metadata: languageName: node linkType: hard +"comment-json@npm:^4.2.5": + version: 4.2.5 + resolution: "comment-json@npm:4.2.5" + dependencies: + array-timsort: "npm:^1.0.3" + core-util-is: "npm:^1.0.3" + esprima: "npm:^4.0.1" + has-own-prop: "npm:^2.0.0" + repeat-string: "npm:^1.6.1" + checksum: 10c0/e22f13f18fcc484ac33c8bc02a3d69c3f9467ae5063fdfb3df7735f83a8d9a2cab6a32b7d4a0c53123413a9577de8e17c8cc88369c433326799558febb34ef9c + languageName: node + linkType: hard + "common-ancestor-path@npm:^1.0.1": version: 1.0.1 resolution: "common-ancestor-path@npm:1.0.1" @@ -25551,6 +25624,19 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-project-structure@npm:^3.7.2": + version: 3.7.2 + resolution: "eslint-plugin-project-structure@npm:3.7.2" + dependencies: + "@typescript-eslint/utils": "npm:^8.8.0" + comment-json: "npm:^4.2.5" + js-yaml: "npm:^4.1.0" + jsonschema: "npm:^1.4.1" + micromatch: "npm:^4.0.8" + checksum: 10c0/bb5d972cb2f24eceae0b5eefc7ccfaed1e0802977bc5ea33d3eb105521b590b5a69b36adcd3124ae67367af6b7798a05b17f06d085deaf9059e53b0839e3621e + languageName: node + linkType: hard + "eslint-plugin-react-hooks@npm:^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": version: 5.0.0-canary-7118f5dd7-20230705 resolution: "eslint-plugin-react-hooks@npm:5.0.0-canary-7118f5dd7-20230705" @@ -32002,6 +32088,13 @@ __metadata: languageName: node linkType: hard +"jsonschema@npm:^1.4.1": + version: 1.4.1 + resolution: "jsonschema@npm:1.4.1" + checksum: 10c0/c3422d3fc7d33ff7234a806ffa909bb6fb5d1cd664bea229c64a1785dc04cbccd5fc76cf547c6ab6dd7881dbcaf3540a6a9f925a5956c61a9cd3e23a3c1796ef + languageName: node + linkType: hard + "jsonwebtoken@npm:9.0.2, jsonwebtoken@npm:^9.0.0": version: 9.0.2 resolution: "jsonwebtoken@npm:9.0.2" @@ -34581,6 +34674,16 @@ __metadata: languageName: node linkType: hard +"micromatch@npm:^4.0.8": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 + languageName: node + linkType: hard + "microseconds@npm:0.2.0": version: 0.2.0 resolution: "microseconds@npm:0.2.0" @@ -44100,6 +44203,7 @@ __metadata: eslint-plugin-jsx-a11y: "npm:^6.8.0" eslint-plugin-prefer-arrow: "npm:^1.2.3" eslint-plugin-prettier: "npm:^5.1.2" + eslint-plugin-project-structure: "npm:^3.7.2" eslint-plugin-react: "npm:^7.33.2" eslint-plugin-react-hooks: "npm:^4.6.0" eslint-plugin-react-refresh: "npm:^0.4.4" From 44a843542c14e7f765114c20d3f2e700e63cf2d5 Mon Sep 17 00:00:00 2001 From: Manish Kr Prasad <85901005+Naprila@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:51:23 +0530 Subject: [PATCH 16/38] Design a promotional poster for twenty. (#7896) ### Points: 300 ### Proof: Screenshot 2024-10-20 at 10 00 57 PM Co-authored-by: Apple --- .../1-design-promotional-poster-20-share.md | 1 + 1 file changed, 1 insertion(+) diff --git a/oss-gg/twenty-design-challenges/1-design-promotional-poster-20-share.md b/oss-gg/twenty-design-challenges/1-design-promotional-poster-20-share.md index 9f1f55ae767e..7bfb7d49382a 100644 --- a/oss-gg/twenty-design-challenges/1-design-promotional-poster-20-share.md +++ b/oss-gg/twenty-design-challenges/1-design-promotional-poster-20-share.md @@ -28,4 +28,5 @@ Your turn 👇 » 17-October-2024 by [Atharva Deshmukh](https://oss.gg/Atharva-3000) poster Link: [poster](https://x.com/0x_atharva/status/1846915861191577697) +» 20-October-2024 by [Naprila](https://oss.gg/Naprila) poster Link: [poster](https://x.com/mkprasad_821/status/1848037527921254625) --- From 8b5b0da77ff3199a91768491aeb4ea3dd787ec36 Mon Sep 17 00:00:00 2001 From: Manish Kr Prasad <85901005+Naprila@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:53:24 +0530 Subject: [PATCH 17/38] Design/Create new Twenty logo, tweet your design. (#7892) ### Points: 300 ### Proof: Screenshot 2024-10-20 at 6 13 00 PM Co-authored-by: Apple --- oss-gg/twenty-design-challenges/2-design-new-logo-twenty.md | 1 + 1 file changed, 1 insertion(+) diff --git a/oss-gg/twenty-design-challenges/2-design-new-logo-twenty.md b/oss-gg/twenty-design-challenges/2-design-new-logo-twenty.md index d67c49b64154..f29319349cbf 100644 --- a/oss-gg/twenty-design-challenges/2-design-new-logo-twenty.md +++ b/oss-gg/twenty-design-challenges/2-design-new-logo-twenty.md @@ -28,5 +28,6 @@ Your turn 👇 » 17-October-2024 by [shlok-py](https://oss.gg/shlok-py) Logo Link: [logo](https://drive.google.com/file/d/1BakHRLJul6DcNbLyeOXgJO9Ap4DpUxO9/view?usp=sharing) » tweet Link: [tweet](https://x.com/koirala_shlok/status/1846910669658247201) +» 20-October-2024 by [Naprila](https://oss.gg/Naprila) Logo Link: [logo](https://drive.google.com/file/d/105fWXNtOkOPkU31AV0FDZKOdrJ8XLwBb/view?usp=drivesdk) » tweet Link: [tweet](https://x.com/mkprasad_821/status/1847978789713695133) --- From b134f62da79a56e7a71407fad9abec83f75f67db Mon Sep 17 00:00:00 2001 From: Manish Kr Prasad <85901005+Naprila@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:55:24 +0530 Subject: [PATCH 18/38] oss.gg: Created a gif about twenty and uploaded to Giphy (#7884) ### Points 150 ### Proof Link to tweet: https://x.com/mkprasad_821/status/1847917157956419690 Link to giphy: https://giphy.com/gifs/uiTAwFJ0BWQsQb7jbM Screenshot 2024-10-20 at 1 49 43 PM Co-authored-by: Apple --- oss-gg/twenty-side-quest/5-gif-magic.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oss-gg/twenty-side-quest/5-gif-magic.md b/oss-gg/twenty-side-quest/5-gif-magic.md index b55bc24fc838..eab5d578430b 100644 --- a/oss-gg/twenty-side-quest/5-gif-magic.md +++ b/oss-gg/twenty-side-quest/5-gif-magic.md @@ -37,4 +37,7 @@ Your turn 👇 » 20-October-2024 by Satesh Charan » Link to gif: https://giphy.com/gifs/rXjvGBrTqu7vvhEsvR + +» 20-October-2024 by Naprila +» Link to gif: https://giphy.com/gifs/uiTAwFJ0BWQsQb7jbM --- From a09c5280ee5e2f21fa0a7005cb22fe93178cf841 Mon Sep 17 00:00:00 2001 From: sateshcharan Date: Sun, 20 Oct 2024 23:56:17 +0530 Subject: [PATCH 19/38] oss.gg - Side quest meme magic completed (#7879) ![image](https://github.com/user-attachments/assets/c2d52346-4fdb-49de-8b70-e3a1da3a7521) --------- Co-authored-by: Charles Bochet --- oss-gg/twenty-side-quest/4-meme-magic.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/oss-gg/twenty-side-quest/4-meme-magic.md b/oss-gg/twenty-side-quest/4-meme-magic.md index feacc0b857a7..7aa0a3b4a0a1 100644 --- a/oss-gg/twenty-side-quest/4-meme-magic.md +++ b/oss-gg/twenty-side-quest/4-meme-magic.md @@ -35,6 +35,11 @@ Your turn 👇 » 16-October-2024 by Harsh Bhat » Link to Tweet: https://x.com/HarshBhatX/status/1844698253104709899 + +» 20-October-2024 by Satesh Charan +» Link to Tweet: https://x.com/sateshcharans/status/1847760124267389357 + » 20-October-2024 by Naprila » Link to Tweet: https://x.com/mkprasad_821/status/1847900277510123706 + --- From f27b1169a1b0b64783f68862ad70c9c93e21e0e7 Mon Sep 17 00:00:00 2001 From: Poorvi Bajpai <150348534+poorvibajpai@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:57:53 +0530 Subject: [PATCH 20/38] meme-magic #7875 created (#7878) Completed the sidequest of meme magic Co-authored-by: Charles Bochet --- oss-gg/twenty-side-quest/4-meme-magic.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/oss-gg/twenty-side-quest/4-meme-magic.md b/oss-gg/twenty-side-quest/4-meme-magic.md index 7aa0a3b4a0a1..eb631acce03e 100644 --- a/oss-gg/twenty-side-quest/4-meme-magic.md +++ b/oss-gg/twenty-side-quest/4-meme-magic.md @@ -35,6 +35,8 @@ Your turn 👇 » 16-October-2024 by Harsh Bhat » Link to Tweet: https://x.com/HarshBhatX/status/1844698253104709899 +» 20-October-2024 by Poorvi Bajpai +» Link to Tweet: https://x.com/poorvi_bajpai/status/1847881362038308992 » 20-October-2024 by Satesh Charan » Link to Tweet: https://x.com/sateshcharans/status/1847760124267389357 From 35bb1a82bab5890d63ead458ec16c8ac31fb5edb Mon Sep 17 00:00:00 2001 From: Manish Kr Prasad <85901005+Naprila@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:58:06 +0530 Subject: [PATCH 21/38] side quest: Like & Re-Tweet oss.gg Launch Tweet (#7877) Description: Liked & Tweeted @twentycrm on X Points: 50 Proof: Link: https://x.com/mkprasad_821/status/1847886807314120762 Screenshot 2024-10-20 at 11 56 54 AM --------- Co-authored-by: Apple --- oss-gg/twenty-side-quest/1-quote-tweet-20-oss-gg-launch.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oss-gg/twenty-side-quest/1-quote-tweet-20-oss-gg-launch.md b/oss-gg/twenty-side-quest/1-quote-tweet-20-oss-gg-launch.md index a0e1421bfd99..7121fb7da638 100644 --- a/oss-gg/twenty-side-quest/1-quote-tweet-20-oss-gg-launch.md +++ b/oss-gg/twenty-side-quest/1-quote-tweet-20-oss-gg-launch.md @@ -46,3 +46,6 @@ Your turn 👇 » 16-October-2024 by Harsh Bhat » Link to Tweet: https://x.com/HarshBhatX/status/1846252536241508392 + +» 20-October-2024 by Naprila +» Link to Tweet: https://x.com/mkprasad_821/status/1847886807314120762 From cc4b060932ce6c05531c35b2ff7a74931203fdc0 Mon Sep 17 00:00:00 2001 From: BOHEUS <56270748+BOHEUS@users.noreply.github.com> Date: Sun, 20 Oct 2024 21:09:28 +0000 Subject: [PATCH 22/38] Typos in docs (#7898) --- .../developers/self-hosting/cloud-providers.mdx | 2 +- .../developers/self-hosting/self-hosting-var.mdx | 14 +++++++------- .../developers/self-hosting/upgrade-guide.mdx | 4 ++-- .../src/content/user-guide/objects/fields.mdx | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/twenty-website/src/content/developers/self-hosting/cloud-providers.mdx b/packages/twenty-website/src/content/developers/self-hosting/cloud-providers.mdx index 08e541a21a19..38cddead7ce9 100644 --- a/packages/twenty-website/src/content/developers/self-hosting/cloud-providers.mdx +++ b/packages/twenty-website/src/content/developers/self-hosting/cloud-providers.mdx @@ -11,7 +11,7 @@ This document is maintained by the community. It might contain issues. ## Kubernetes via Terraform and Manifests -Community-led documentation for Kubernetes deployment is available (here)[https://github.com/twentyhq/twenty/tree/main/packages/twenty-docker/k8s] +Community-led documentation for Kubernetes deployment is available [here](https://github.com/twentyhq/twenty/tree/main/packages/twenty-docker/k8s) ## Render diff --git a/packages/twenty-website/src/content/developers/self-hosting/self-hosting-var.mdx b/packages/twenty-website/src/content/developers/self-hosting/self-hosting-var.mdx index d679096f80a7..18a5ecd4ac85 100644 --- a/packages/twenty-website/src/content/developers/self-hosting/self-hosting-var.mdx +++ b/packages/twenty-website/src/content/developers/self-hosting/self-hosting-var.mdx @@ -60,7 +60,7 @@ yarn command:prod cron:calendar:calendar-event-list-fetch ['REFRESH_TOKEN_COOL_DOWN', '1m', 'Refresh token cooldown'], ['FILE_TOKEN_SECRET', '', 'Secret used for the file tokens'], ['FILE_TOKEN_EXPIRES_IN', '1d', 'File token expiration time'], - ['API_TOKEN_EXPIRES_IN', '1000y', 'Api token expiration time'], + ['API_TOKEN_EXPIRES_IN', '1000y', 'API token expiration time'], ]}> ### Auth @@ -91,10 +91,10 @@ yarn command:prod cron:calendar:calendar-event-list-fetch ['EMAIL_FROM_NAME', 'John from YourDomain', 'Global name From: header used to send emails'], ['EMAIL_SYSTEM_ADDRESS', 'system@yourdomain.com', 'Email address used as a destination to send internal system notification'], ['EMAIL_DRIVER', 'logger', "Email driver: 'logger' (to log emails in console) or 'smtp'"], - ['EMAIL_SMTP_HOST', '', 'Email Smtp Host'], - ['EMAIL_SMTP_PORT', '', 'Email Smtp Port'], - ['EMAIL_SMTP_USER', '', 'Email Smtp User'], - ['EMAIL_SMTP_PASSWORD', '', 'Email Smtp Password'], + ['EMAIL_SMTP_HOST', '', 'Email SMTP Host'], + ['EMAIL_SMTP_PORT', '', 'Email SMTP Port'], + ['EMAIL_SMTP_USER', '', 'Email SMTP User'], + ['EMAIL_SMTP_PASSWORD', '', 'Email SMTP Password'], ]}> #### Email SMTP Server configuration examples @@ -143,7 +143,7 @@ yarn command:prod cron:calendar:calendar-event-list-fetch ['STORAGE_S3_ENDPOINT', '', 'Use if a different Endpoint is needed (for example Google)'], ['STORAGE_S3_ACCESS_KEY_ID', '', 'Optional depending on the authentication method'], ['STORAGE_S3_SECRET_ACCESS_KEY', '', 'Optional depending on the authentication method'], - ['STORAGE_LOCAL_PATH', '.local-storage', 'data path (local storage)'], + ['STORAGE_LOCAL_PATH', '.local-storage', 'Data path (local storage)'], ]}> ### Custom Code Execution @@ -201,7 +201,7 @@ This feature is WIP and is not yet useful for most users. ', 'Suport chat key'], + ['SUPPORT_FRONT_HMAC_KEY', '', 'Support chat key'], ['SUPPORT_FRONT_CHAT_ID', '', 'Support chat id'], ]}> diff --git a/packages/twenty-website/src/content/developers/self-hosting/upgrade-guide.mdx b/packages/twenty-website/src/content/developers/self-hosting/upgrade-guide.mdx index 2379fb2fc42e..3b4ff6123188 100644 --- a/packages/twenty-website/src/content/developers/self-hosting/upgrade-guide.mdx +++ b/packages/twenty-website/src/content/developers/self-hosting/upgrade-guide.mdx @@ -84,7 +84,7 @@ yarn command:prod upgrade-0.30 ``` The `yarn database:migrate:prod` command will apply the migrations to the database structure (core and metadata schemas) -The `yarn command:prod upgrade-30` takes care of the data migration of all workspaces. +The `yarn command:prod upgrade-0.30` takes care of the data migration of all workspaces. # v0.30.0 to v0.31.0 @@ -97,7 +97,7 @@ yarn command:prod upgrade-0.31 ``` The `yarn database:migrate:prod` command will apply the migrations to the database structure (core and metadata schemas) -The `yarn command:prod upgrade-31` takes care of the data migration of all workspaces. +The `yarn command:prod upgrade-0.31` takes care of the data migration of all workspaces. # v0.31.0 to v0.32.0 diff --git a/packages/twenty-website/src/content/user-guide/objects/fields.mdx b/packages/twenty-website/src/content/user-guide/objects/fields.mdx index 69f7c4a961df..7039db1d6095 100644 --- a/packages/twenty-website/src/content/user-guide/objects/fields.mdx +++ b/packages/twenty-website/src/content/user-guide/objects/fields.mdx @@ -72,7 +72,7 @@ Here's how you can do it: 2. To the right of the line, three vertically aligned dots symbolize a menu button. Click on this to unveil a dropdown list of options. -3. In the dropdown menu, find and click on the "deactivate" option. +3. In the dropdown menu, find and click on the "Deactivate" option. From d6810c3b428b6a9a7a035c681f35333c50d6a74f Mon Sep 17 00:00:00 2001 From: Ngan Phan Date: Sun, 20 Oct 2024 23:33:59 -0700 Subject: [PATCH 23/38] fix: Custom fields lacks empty tag (#7777) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes this issue #7250 --------- Co-authored-by: Félix Malfait --- .../utils/__tests__/isFieldValueEmpty.test.ts | 12 ++++++++++++ .../record-field/utils/isFieldValueEmpty.ts | 13 ++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/utils/__tests__/isFieldValueEmpty.test.ts b/packages/twenty-front/src/modules/object-record/record-field/utils/__tests__/isFieldValueEmpty.test.ts index 07761aef8822..db247716ab9a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/utils/__tests__/isFieldValueEmpty.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/utils/__tests__/isFieldValueEmpty.test.ts @@ -46,6 +46,18 @@ describe('isFieldValueEmpty', () => { fieldValue: { foo: 'bar' }, }), ).toBe(false); + expect( + isFieldValueEmpty({ + fieldDefinition: relationFieldDefinition, + fieldValue: [], + }), + ).toBe(true); + expect( + isFieldValueEmpty({ + fieldDefinition: relationFieldDefinition, + fieldValue: [{ id: '123' }], + }), + ).toBe(false); }); it('should return correct value for select field', () => { diff --git a/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueEmpty.ts b/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueEmpty.ts index 93ee5eaa5458..e8e3ebe3fb86 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueEmpty.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueEmpty.ts @@ -1,4 +1,4 @@ -import { isString } from '@sniptt/guards'; +import { isArray, isNonEmptyArray, isString } from '@sniptt/guards'; import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; @@ -58,7 +58,6 @@ export const isFieldValueEmpty = ({ isFieldNumber(fieldDefinition) || isFieldRating(fieldDefinition) || isFieldBoolean(fieldDefinition) || - isFieldRelation(fieldDefinition) || isFieldRawJson(fieldDefinition) || isFieldRichText(fieldDefinition) || isFieldPosition(fieldDefinition) @@ -73,11 +72,19 @@ export const isFieldValueEmpty = ({ ); } + if (isFieldRelation(fieldDefinition)) { + if (isArray(fieldValue)) { + return !isNonEmptyArray(fieldValue); + } + return isValueEmpty(fieldValue); + } + if (isFieldMultiSelect(fieldDefinition) || isFieldArray(fieldDefinition)) { return ( !isFieldArrayValue(fieldValue) || !isFieldMultiSelectValue(fieldValue, selectOptionValues) || - !isDefined(fieldValue) + !isDefined(fieldValue) || + !isNonEmptyArray(fieldValue) ); } From ae1d53aa2943255af72a24d10dba035ae3b74083 Mon Sep 17 00:00:00 2001 From: Rajeev Dewangan <63413883+rajeevDewangan@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:07:00 +0530 Subject: [PATCH 24/38] Write-a-blog-post-about-Twenty (#7902) What side quest are you solving: Write a blog post about Twenty Description: Shared my experience using Twenty in a detailed blog post Points: 750 Proof: link : https://open.substack.com/pub/rajeevdewangan/p/our-experience-using-twenty-an-open?r=4lly3x&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true ![Screenshot 2024-10-21 103524](https://github.com/user-attachments/assets/9475c262-8c5e-4a74-b2c7-e690e72daba4) --- Write-a-blog-post-about-Twenty | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Write-a-blog-post-about-Twenty diff --git a/Write-a-blog-post-about-Twenty b/Write-a-blog-post-about-Twenty new file mode 100644 index 000000000000..86325c0af708 --- /dev/null +++ b/Write-a-blog-post-about-Twenty @@ -0,0 +1,2 @@ +Description: +Shared my experience using Twenty in a detailed blog post From f3ec6a759fb17df5e89c485ebf74afb7b673e46b Mon Sep 17 00:00:00 2001 From: Bhavesh Mishra <69065938+thefool76@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:11:19 +0530 Subject: [PATCH 25/38] OSS.GG Content creation challenge (#7859) I have the content creation challenge of twenty I have published a detailed Youtube walkthrough to Twenty Dashboard and Created a Blog on Hashnode about Twenty Crm with step by step guide to use Twenty. Below are the task links 1. Create a YouTube Video about Twenty showcasing a specific way to use Twenty effectively. Points: 750 [Watch here](https://youtu.be/KuAycGuW698?si=TyKGVyrydLzof2RI) 2. Write a blog post about sharing your experience using Twenty in a detailed format on any platform. Points: 750 [Click here](https://k5lo7h.hashnode.dev/twenty-crm-a-fresh-start-for-modern-businesses) Total Points - 1500 --- .../1-create-youtube-video-about-20.md | 4 +++- .../twenty-content-challenges/2-write-blog-post-about-20.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/oss-gg/twenty-content-challenges/1-create-youtube-video-about-20.md b/oss-gg/twenty-content-challenges/1-create-youtube-video-about-20.md index 455b5e35bae3..2f8d1d1553ed 100644 --- a/oss-gg/twenty-content-challenges/1-create-youtube-video-about-20.md +++ b/oss-gg/twenty-content-challenges/1-create-youtube-video-about-20.md @@ -18,4 +18,6 @@ Your turn 👇 » 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) YouTube Link: [YouTube](https://twenty.com/) ---- \ No newline at end of file +» 19-October-2024 by [Thefool76](https://oss.gg/thefool76) YouTube Link: [YouTube](https://youtu.be/KuAycGuW698?si=q-YxcukbbYuO8BWf) + +--- diff --git a/oss-gg/twenty-content-challenges/2-write-blog-post-about-20.md b/oss-gg/twenty-content-challenges/2-write-blog-post-about-20.md index a4c4e6bee944..ca36278ff3f6 100644 --- a/oss-gg/twenty-content-challenges/2-write-blog-post-about-20.md +++ b/oss-gg/twenty-content-challenges/2-write-blog-post-about-20.md @@ -18,4 +18,6 @@ Your turn 👇 » 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) blog Link: [blog](https://twenty.com/) ---- \ No newline at end of file +» 19-October-2024 by [Thefool76](https://oss.gg/thefool76) blog Link: [blog](https://k5lo7h.hashnode.dev/twenty-crm-a-fresh-start-for-modern-businesses) + +--- From fc6748de0a2abc941cfc6f882fab0908caa03d7a Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Mon, 21 Oct 2024 11:51:54 +0200 Subject: [PATCH 26/38] Add modal to confirm workflow draft version overriding (#7758) In this PR: - Allow the `` to take additional buttons to display between the cancel and the confirm buttons. - Create a modal that's displayed when the user tries wants to use a workflow version as draft while a draft version already exists. The displayed modal contains a link to the current draft version and a button to confirm the overriding of the current draft version. A demo: https://github.com/user-attachments/assets/6349f418-1b11-45b3-9f5e-061ca74c2966 Closes twentyhq/private-issues#114 --- .../modal/components/ConfirmationModal.tsx | 8 ++- ...OverrideWorkflowDraftConfirmationModal.tsx | 62 +++++++++++++++++++ .../RecordShowPageWorkflowVersionHeader.tsx | 33 ++++++---- ...rideWorkflowDraftConfirmationModalState.ts | 7 +++ 4 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 packages/twenty-front/src/modules/workflow/components/OverrideWorkflowDraftConfirmationModal.tsx create mode 100644 packages/twenty-front/src/modules/workflow/states/openOverrideWorkflowDraftConfirmationModalState.ts diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx index 04a80a1c827a..7b75faec18e5 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx @@ -25,6 +25,7 @@ export type ConfirmationModalProps = { confirmationPlaceholder?: string; confirmationValue?: string; confirmButtonAccent?: ButtonAccent; + AdditionalButtons?: React.ReactNode; }; const StyledConfirmationModal = styled(Modal)` @@ -33,7 +34,8 @@ const StyledConfirmationModal = styled(Modal)` height: auto; `; -const StyledCenteredButton = styled(Button)` +export const StyledCenteredButton = styled(Button)` + box-sizing: border-box; justify-content: center; margin-top: ${({ theme }) => theme.spacing(2)}; `; @@ -68,6 +70,7 @@ export const ConfirmationModal = ({ confirmationValue, confirmationPlaceholder, confirmButtonAccent = 'danger', + AdditionalButtons, }: ConfirmationModalProps) => { const [inputConfirmationValue, setInputConfirmationValue] = useState(''); @@ -138,6 +141,9 @@ export const ConfirmationModal = ({ title="Cancel" fullWidth /> + + {AdditionalButtons} + ; +}) => { + const [ + openOverrideWorkflowDraftConfirmationModal, + setOpenOverrideWorkflowDraftConfirmationModal, + ] = useRecoilState(openOverrideWorkflowDraftConfirmationModalState); + + const { updateOneRecord: updateOneWorkflowVersion } = + useUpdateOneRecord({ + objectNameSingular: CoreObjectNameSingular.WorkflowVersion, + }); + + const handleOverrideDraft = async () => { + await updateOneWorkflowVersion({ + idToUpdate: draftWorkflowVersionId, + updateOneRecordInput: workflowVersionUpdateInput, + }); + }; + + return ( + <> + { + setOpenOverrideWorkflowDraftConfirmationModal(false); + }} + variant="secondary" + title="Go to Draft" + fullWidth + /> + } + /> + + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowVersionHeader.tsx b/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowVersionHeader.tsx index 79cbe7c27f77..e796c4a88cae 100644 --- a/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowVersionHeader.tsx +++ b/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowVersionHeader.tsx @@ -1,13 +1,15 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; -import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { Button } from '@/ui/input/button/components/Button'; +import { OverrideWorkflowDraftConfirmationModal } from '@/workflow/components/OverrideWorkflowDraftConfirmationModal'; import { useActivateWorkflowVersion } from '@/workflow/hooks/useActivateWorkflowVersion'; import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion'; import { useDeactivateWorkflowVersion } from '@/workflow/hooks/useDeactivateWorkflowVersion'; import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; +import { openOverrideWorkflowDraftConfirmationModalState } from '@/workflow/states/openOverrideWorkflowDraftConfirmationModalState'; import { Workflow, WorkflowVersion } from '@/workflow/types/Workflow'; +import { useSetRecoilState } from 'recoil'; import { IconPencil, IconPlayerStop, IconPower, isDefined } from 'twenty-ui'; export const RecordShowPageWorkflowVersionHeader = ({ @@ -46,6 +48,8 @@ export const RecordShowPageWorkflowVersionHeader = ({ skip: !isDefined(workflowVersion), limit: 1, }); + const draftWorkflowVersion: WorkflowVersion | undefined = + draftWorkflowVersions[0]; const showUseAsDraftButton = !loadingDraftWorkflowVersions && @@ -57,7 +61,7 @@ export const RecordShowPageWorkflowVersionHeader = ({ workflowVersionRelatedWorkflowQuery.record.lastPublishedVersionId; const hasAlreadyDraftVersion = - !loadingDraftWorkflowVersions && draftWorkflowVersions.length > 0; + !loadingDraftWorkflowVersions && isDefined(draftWorkflowVersion); const isWaitingForWorkflowVersion = !isDefined(workflowVersion); @@ -65,10 +69,9 @@ export const RecordShowPageWorkflowVersionHeader = ({ const { deactivateWorkflowVersion } = useDeactivateWorkflowVersion(); const { createNewWorkflowVersion } = useCreateNewWorkflowVersion(); - const { updateOneRecord: updateOneWorkflowVersion } = - useUpdateOneRecord({ - objectNameSingular: CoreObjectNameSingular.WorkflowVersion, - }); + const setOpenOverrideWorkflowDraftConfirmationModal = useSetRecoilState( + openOverrideWorkflowDraftConfirmationModalState, + ); return ( <> @@ -80,13 +83,7 @@ export const RecordShowPageWorkflowVersionHeader = ({ disabled={isWaitingForWorkflowVersion} onClick={async () => { if (hasAlreadyDraftVersion) { - await updateOneWorkflowVersion({ - idToUpdate: draftWorkflowVersions[0].id, - updateOneRecordInput: { - trigger: workflowVersion.trigger, - steps: workflowVersion.steps, - }, - }); + setOpenOverrideWorkflowDraftConfirmationModal(true); } else { await createNewWorkflowVersion({ workflowId: workflowVersion.workflow.id, @@ -125,6 +122,16 @@ export const RecordShowPageWorkflowVersionHeader = ({ }} /> ) : null} + + {isDefined(workflowVersion) && isDefined(draftWorkflowVersion) ? ( + + ) : null} ); }; diff --git a/packages/twenty-front/src/modules/workflow/states/openOverrideWorkflowDraftConfirmationModalState.ts b/packages/twenty-front/src/modules/workflow/states/openOverrideWorkflowDraftConfirmationModalState.ts new file mode 100644 index 000000000000..1320a964207d --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/states/openOverrideWorkflowDraftConfirmationModalState.ts @@ -0,0 +1,7 @@ +import { createState } from 'twenty-ui'; + +export const openOverrideWorkflowDraftConfirmationModalState = + createState({ + key: 'openOverrideWorkflowDraftConfirmationModalState', + defaultValue: false, + }); From b914182b78b40acbaa8cb10209cee8c91e57f0d2 Mon Sep 17 00:00:00 2001 From: shubham yadav <126192924+yadavshubham01@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:32:14 +0530 Subject: [PATCH 27/38] Update workflows to optimize CI processes (#7828) This Pull Request addresses the need to optimize our Continuous Integration (CI) workflows for Playwright tests and release processes. The changes implemented aim to reduce unnecessary resource usage by conditionally executing jobs based on relevant file changes and Implement https://github.com/tj-actions/changed-files step ## Changes logs - Updated `ci-test-docker-compose.yaml , ci-chrome-extension.yaml ` to check for changed files before running tests. - Updated `ci-front.yaml , ci-utils.yaml , ci-website.yaml , ci-server.yaml` to check for changed files before running tests. - Enhanced `playwright.yml` to skip unnecessary tests based on file changes. --- .github/workflows/ci-chrome-extension.yaml | 24 +++- .github/workflows/ci-front.yaml | 134 ++++++++++++++++-- .github/workflows/ci-server.yaml | 43 ++++-- .github/workflows/ci-test-docker-compose.yaml | 14 +- .github/workflows/ci-utils.yaml | 14 ++ .github/workflows/ci-website.yaml | 25 +++- .github/workflows/playwright.yml.bak | 16 +++ 7 files changed, 239 insertions(+), 31 deletions(-) diff --git a/.github/workflows/ci-chrome-extension.yaml b/.github/workflows/ci-chrome-extension.yaml index a78be9415597..071104d31cb7 100644 --- a/.github/workflows/ci-chrome-extension.yaml +++ b/.github/workflows/ci-chrome-extension.yaml @@ -3,13 +3,9 @@ on: push: branches: - main - paths: - - 'package.json' - - 'packages/twenty-chrome-extension/**' + pull_request: - paths: - - 'package.json' - - 'packages/twenty-chrome-extension/**' + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -26,7 +22,23 @@ jobs: with: access_token: ${{ github.token }} - uses: actions/checkout@v4 + + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + package.json + packages/twenty-chrome-extension/** + - name: Install dependencies + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Chrome Extension / Run build + if: steps.changed-files.outputs.changed == 'true' run: npx nx build twenty-chrome-extension + + - name: Mark as Valid if No Changes + if: steps.changed-files.outputs.changed != 'true' + run: | + echo "No relevant changes detected. Marking as valid." diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index 506a6dce0e5e..d0a8a4c360ed 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -3,15 +3,9 @@ on: push: branches: - main - paths: - - 'package.json' - - 'packages/twenty-front/**' - - 'packages/twenty-ui/**' + pull_request: - paths: - - 'package.json' - - 'packages/twenty-front/**' - - 'packages/twenty-ui/**' + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -29,20 +23,81 @@ jobs: access_token: ${{ github.token }} - name: Fetch local actions uses: actions/checkout@v4 + + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + package.json + packages/twenty-front/** + packages/twenty-ui/** + + - name: Skip if no relevant changes + if: steps.changed-files.outputs.any_changed == 'false' + run: echo "No relevant changes. Skipping CI." + - name: Install dependencies + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Diagnostic disk space issue + if: steps.changed-files.outputs.any_changed == 'true' run: df -h - name: Front / Restore Storybook Task Cache + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/task-cache with: tag: scope:frontend tasks: storybook:build - name: Front / Write .env + if: steps.changed-files.outputs.any_changed == 'true' run: npx nx reset:env twenty-front - name: Front / Build storybook + if: steps.changed-files.outputs.any_changed == 'true' run: npx nx storybook:build twenty-front front-sb-test: + + runs-on: ci-8-cores + timeout-minutes: 60 + needs: front-sb-build + strategy: + matrix: + storybook_scope: [pages, modules] + env: + REACT_APP_SERVER_BASE_URL: http://localhost:3000 + NX_REJECT_UNKNOWN_LOCAL_CACHE: 0 + steps: + - name: Fetch local actions + uses: actions/checkout@v4 + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + packages/twenty-front/** + - name: Skip if no relevant changes + if: steps.changed-files.outputs.any_changed == 'false' + run: echo "No relevant changes. Skipping CI." + + - name: Install dependencies + if: steps.changed-files.outputs.any_changed == 'true' + uses: ./.github/workflows/actions/yarn-install + - name: Install Playwright + if: steps.changed-files.outputs.any_changed == 'true' + run: cd packages/twenty-front && npx playwright install + - name: Front / Restore Storybook Task Cache + if: steps.changed-files.outputs.any_changed == 'true' + uses: ./.github/workflows/actions/task-cache + with: + tag: scope:frontend + tasks: storybook:build + - name: Front / Write .env + if: steps.changed-files.outputs.any_changed == 'true' + run: npx nx reset:env twenty-front + - name: Run storybook tests + if: steps.changed-files.outputs.any_changed == 'true' + run: npx nx storybook:serve-and-test:static twenty-front --configuration=${{ matrix.storybook_scope }} + front-sb-test-shipfox: runs-on: shipfox-8vcpu-ubuntu-2204 timeout-minutes: 60 needs: front-sb-build @@ -55,18 +110,35 @@ jobs: steps: - name: Fetch local actions uses: actions/checkout@v4 + + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + packages/twenty-front/** + + - name: Skip if no relevant changes + if: steps.changed-files.outputs.any_changed == 'false' + run: echo "No relevant changes. Skipping CI." + - name: Install dependencies + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Install Playwright + if: steps.changed-files.outputs.any_changed == 'true' run: cd packages/twenty-front && npx playwright install - name: Front / Restore Storybook Task Cache + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/task-cache with: tag: scope:frontend tasks: storybook:build - name: Front / Write .env + if: steps.changed-files.outputs.any_changed == 'true' run: npx nx reset:env twenty-front - name: Run storybook tests + if: steps.changed-files.outputs.any_changed == 'true' run: npx nx storybook:serve-and-test:static twenty-front --configuration=${{ matrix.storybook_scope }} front-sb-test-performance: runs-on: shipfox-8vcpu-ubuntu-2204 @@ -77,13 +149,28 @@ jobs: steps: - name: Fetch local actions uses: actions/checkout@v4 + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + packages/twenty-front/** + + - name: Skip if no relevant changes + if: steps.changed-files.outputs.any_changed == 'false' + run: echo "No relevant changes. Skipping CI." + - name: Install dependencies + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Install Playwright + if: steps.changed-files.outputs.any_changed == 'true' run: cd packages/twenty-front && npx playwright install - name: Front / Write .env + if: steps.changed-files.outputs.any_changed == 'true' run: npx nx reset:env twenty-front - name: Run storybook tests + if: steps.changed-files.outputs.any_changed == 'true' run: npx nx storybook:serve-and-test:static:performance twenty-front front-chromatic-deployment: if: contains(github.event.pull_request.labels.*.name, 'run-chromatic') || github.event_name == 'push' @@ -97,19 +184,35 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + packages/twenty-front/** + + - name: Skip if no relevant changes + if: steps.changed-files.outputs.any_changed == 'false' + run: echo "No relevant changes. Skipping CI." + - name: Install dependencies + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Front / Restore Storybook Task Cache + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/task-cache with: tag: scope:frontend tasks: storybook:build - name: Front / Write .env + if: steps.changed-files.outputs.any_changed == 'true' run: | cd packages/twenty-front touch .env echo "REACT_APP_SERVER_BASE_URL: $REACT_APP_SERVER_BASE_URL" >> .env - name: Publish to Chromatic + if: steps.changed-files.outputs.any_changed == 'true' run: npx nx run twenty-front:chromatic:ci front-task: runs-on: ubuntu-latest @@ -127,19 +230,34 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + packages/twenty-front/** + + - name: Skip if no relevant changes + if: steps.changed-files.outputs.any_changed == 'false' + run: echo "No relevant changes. Skipping CI." + - name: Install dependencies + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Front / Restore ${{ matrix.task }} task cache + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/task-cache with: tag: scope:frontend tasks: ${{ matrix.task }} - name: Reset .env + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/nx-affected with: tag: scope:frontend tasks: reset:env - name: Run ${{ matrix.task }} task + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/nx-affected with: tag: scope:frontend diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml index 074d63fdda40..101e1df3b47f 100644 --- a/.github/workflows/ci-server.yaml +++ b/.github/workflows/ci-server.yaml @@ -3,15 +3,9 @@ on: push: branches: - main - paths: - - 'package.json' - - 'packages/twenty-server/**' - - 'packages/twenty-emails/**' + pull_request: - paths: - - 'package.json' - - 'packages/twenty-server/**' - - 'packages/twenty-emails/**' + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -38,22 +32,35 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: 'package.json, packages/twenty-server/**, packages/twenty-emails/**' + - name: Install dependencies + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Server / Restore Task Cache + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/task-cache with: tag: scope:backend - name: Server / Run lint & typecheck + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/nx-affected with: tag: scope:backend tasks: lint,typecheck - name: Server / Build + if: steps.changed-files.outputs.changed == 'true' run: npx nx build twenty-server - name: Server / Write .env + if: steps.changed-files.outputs.changed == 'true' run: npx nx reset:env twenty-server - name: Worker / Run + if: steps.changed-files.outputs.changed == 'true' run: npx nx run twenty-server:worker:ci server-test: @@ -66,13 +73,23 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: 'package.json, packages/twenty-server/**, packages/twenty-emails/**' + - name: Install dependencies + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Server / Restore Task Cache + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/task-cache with: tag: scope:backend - name: Server / Run Tests + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/nx-affected with: tag: scope:backend @@ -100,13 +117,23 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: 'package.json, packages/twenty-server/**, packages/twenty-emails/**' + - name: Install dependencies + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Server / Restore Task Cache + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/task-cache with: tag: scope:backend - name: Server / Run Integration Tests + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/nx-affected with: tag: scope:backend diff --git a/.github/workflows/ci-test-docker-compose.yaml b/.github/workflows/ci-test-docker-compose.yaml index 1496425c8511..2ff08a9e17f6 100644 --- a/.github/workflows/ci-test-docker-compose.yaml +++ b/.github/workflows/ci-test-docker-compose.yaml @@ -1,8 +1,7 @@ name: 'Test Docker Compose' on: pull_request: - paths: - - 'packages/twenty-docker/**' + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -13,8 +12,19 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + packages/twenty-docker/** + docker-compose.yml + - name: Skip if no relevant changes + if: steps.changed-files.outputs.any_changed != 'true' + run: echo "No relevant changes detected. Marking as valid." - name: Run compose + if: steps.changed-files.outputs.any_changed == 'true' run: | echo "Patching docker-compose.yml..." # change image to localbuild using yq diff --git a/.github/workflows/ci-utils.yaml b/.github/workflows/ci-utils.yaml index fccfca98d8ab..6cbd99b28803 100644 --- a/.github/workflows/ci-utils.yaml +++ b/.github/workflows/ci-utils.yaml @@ -23,9 +23,16 @@ jobs: if: github.event.action != 'closed' steps: - uses: actions/checkout@v4 + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: 'packages/twenty-utils/**' - name: Install dependencies + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Utils / Run Danger.js + if: steps.changed-files.outputs.changed == 'true' run: cd packages/twenty-utils && npx nx danger:ci env: DANGER_GITHUB_API_TOKEN: ${{ github.token }} @@ -35,9 +42,16 @@ jobs: if: github.event.action == 'closed' && github.event.pull_request.merged == true steps: - uses: actions/checkout@v4 + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: 'packages/twenty-utils/**' - name: Install dependencies + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Run congratulate-dangerfile.js + if: steps.changed-files.outputs.changed == 'true' run: cd packages/twenty-utils && npx nx danger:congratulate env: DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci-website.yaml b/.github/workflows/ci-website.yaml index d79345f3bf53..ce39d66ca79b 100644 --- a/.github/workflows/ci-website.yaml +++ b/.github/workflows/ci-website.yaml @@ -3,13 +3,10 @@ on: push: branches: - main - paths: - - 'package.json' - - 'packages/twenty-website/**' + pull_request: - paths: - - 'package.json' - - 'packages/twenty-website/**' + + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -27,13 +24,27 @@ jobs: - 5432:5432 steps: - uses: actions/checkout@v4 + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: 'package.json, packages/twenty-website/**' + - name: Install dependencies + if: steps.changed-files.outputs.changed == 'true' uses: ./.github/workflows/actions/yarn-install + - name: Website / Run migrations + if: steps.changed-files.outputs.changed == 'true' run: npx nx database:migrate twenty-website env: DATABASE_PG_URL: postgres://twenty:twenty@localhost:5432/default - name: Website / Build Website + if: steps.changed-files.outputs.changed == 'true' run: npx nx build twenty-website env: - DATABASE_PG_URL: postgres://twenty:twenty@localhost:5432/default \ No newline at end of file + DATABASE_PG_URL: postgres://twenty:twenty@localhost:5432/default + + - name: Mark as VALID + if: steps.changed-files.outputs.changed != 'true' # If no changes, mark as valid + run: echo "No relevant changes detected. CI is valid." \ No newline at end of file diff --git a/.github/workflows/playwright.yml.bak b/.github/workflows/playwright.yml.bak index cffb50287629..fc45955bc7ab 100644 --- a/.github/workflows/playwright.yml.bak +++ b/.github/workflows/playwright.yml.bak @@ -13,11 +13,27 @@ jobs: - uses: actions/setup-node@v4 with: node-version: lts/* + + - name: Check for changed files + id: changed-files + uses: tj-actions/changed-files@v11 + with: + files: | + packages/** # Adjust this to your relevant directories + playwright.config.ts # Include any relevant config files + + - name: Skip if no relevant changes + if: steps.changed-files.outputs.any_changed != 'true' + run: echo "No relevant changes detected. Marking as valid." + - name: Install dependencies + if: steps.changed-files.outputs.any_changed == 'true' run: npm install -g yarn && yarn - name: Install Playwright Browsers + if: steps.changed-files.outputs.any_changed == 'true' run: yarn playwright install --with-deps - name: Run Playwright tests + if: steps.changed-files.outputs.any_changed == 'true' run: yarn test:e2e companies - uses: actions/upload-artifact@v4 if: always() From e7eeb3b8201142ca963e717bb2f0659a3ab94795 Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Mon, 21 Oct 2024 12:04:44 +0200 Subject: [PATCH 28/38] Add Workflow Run show page (#7719) In this PR: - Display a workflow version visualizer for the version of the workflow the run was executed on. - Display the output of the run as code. https://github.com/user-attachments/assets/d617300a-bff4-4328-a35c-291dc86d81cf --- .../hooks/useRecordShowContainerTabs.ts | 29 ++- .../SettingsServerlessFunctionCodeEditor.tsx | 130 ++++++++++++++ ...sServerlessFunctionCodeEditorContainer.tsx | 11 ++ ...ettingsServerlessFunctionCodeEditorTab.tsx | 13 +- .../SettingsServerlessFunctionTestTab.tsx | 44 ++--- .../code-editor/components/CodeEditor.tsx | 165 ++++-------------- .../components/ShowPageSubContainer.tsx | 10 ++ .../WorkflowRunOutputVisualizer.tsx | 32 ++++ .../WorkflowRunVersionVisualizer.tsx | 29 +++ .../modules/workflow/hooks/useWorkflowRun.tsx | 16 ++ .../src/modules/workflow/types/Workflow.ts | 22 +++ .../display/icon/components/TablerIcons.ts | 1 + 12 files changed, 334 insertions(+), 168 deletions(-) create mode 100644 packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditor.tsx create mode 100644 packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditorContainer.tsx create mode 100644 packages/twenty-front/src/modules/workflow/components/WorkflowRunOutputVisualizer.tsx create mode 100644 packages/twenty-front/src/modules/workflow/components/WorkflowRunVersionVisualizer.tsx create mode 100644 packages/twenty-front/src/modules/workflow/hooks/useWorkflowRun.tsx diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerTabs.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerTabs.ts index 1d029f4877f8..a1d6a81d2e2f 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerTabs.ts +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerTabs.ts @@ -8,6 +8,7 @@ import { IconMail, IconNotes, IconPaperclip, + IconPrinter, IconSettings, IconTimelineEvent, } from 'twenty-ui'; @@ -26,6 +27,10 @@ export const useRecordShowContainerTabs = ( const isWorkflowVersion = isWorkflowEnabled && targetObjectNameSingular === CoreObjectNameSingular.WorkflowVersion; + const isWorkflowRun = + isWorkflowEnabled && + targetObjectNameSingular === CoreObjectNameSingular.WorkflowRun; + const isWorkflowRelated = isWorkflow || isWorkflowVersion || isWorkflowRun; const isCompanyOrPerson = [ CoreObjectNameSingular.Company, @@ -54,7 +59,7 @@ export const useRecordShowContainerTabs = ( id: 'timeline', title: 'Timeline', Icon: IconTimelineEvent, - hide: isInRightDrawer || isWorkflow || isWorkflowVersion, + hide: isInRightDrawer || isWorkflowRelated, }, { id: 'tasks', @@ -63,8 +68,7 @@ export const useRecordShowContainerTabs = ( hide: targetObjectNameSingular === CoreObjectNameSingular.Note || targetObjectNameSingular === CoreObjectNameSingular.Task || - isWorkflow || - isWorkflowVersion, + isWorkflowRelated, }, { id: 'notes', @@ -73,14 +77,13 @@ export const useRecordShowContainerTabs = ( hide: targetObjectNameSingular === CoreObjectNameSingular.Note || targetObjectNameSingular === CoreObjectNameSingular.Task || - isWorkflow || - isWorkflowVersion, + isWorkflowRelated, }, { id: 'files', title: 'Files', Icon: IconPaperclip, - hide: isWorkflow || isWorkflowVersion, + hide: isWorkflowRelated, }, { id: 'emails', @@ -102,9 +105,21 @@ export const useRecordShowContainerTabs = ( }, { id: 'workflowVersion', - title: 'Workflow Version', + title: 'Flow', Icon: IconSettings, hide: !isWorkflowVersion, }, + { + id: 'workflowRunOutput', + title: 'Output', + Icon: IconPrinter, + hide: !isWorkflowRun, + }, + { + id: 'workflowRunFlow', + title: 'Flow', + Icon: IconSettings, + hide: !isWorkflowRun, + }, ]; }; diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditor.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditor.tsx new file mode 100644 index 000000000000..7641d8f46d38 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditor.tsx @@ -0,0 +1,130 @@ +import { SettingsServerlessFunctionCodeEditorContainer } from '@/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditorContainer'; +import { useGetAvailablePackages } from '@/settings/serverless-functions/hooks/useGetAvailablePackages'; +import { CodeEditor } from '@/ui/input/code-editor/components/CodeEditor'; +import { EditorProps, Monaco } from '@monaco-editor/react'; +import dotenv from 'dotenv'; +import { editor, MarkerSeverity } from 'monaco-editor'; +import { AutoTypings } from 'monaco-editor-auto-typings'; +import { isDefined } from '~/utils/isDefined'; + +export type File = { + language: string; + content: string; + path: string; +}; + +type SettingsServerlessFunctionCodeEditorProps = Omit< + EditorProps, + 'onChange' +> & { + currentFilePath: string; + files: File[]; + onChange: (value: string) => void; + setIsCodeValid: (isCodeValid: boolean) => void; +}; + +export const SettingsServerlessFunctionCodeEditor = ({ + currentFilePath, + files, + onChange, + setIsCodeValid, + height = 450, + options = undefined, +}: SettingsServerlessFunctionCodeEditorProps) => { + const { availablePackages } = useGetAvailablePackages(); + + const currentFile = files.find((file) => file.path === currentFilePath); + const environmentVariablesFile = files.find((file) => file.path === '.env'); + + const handleEditorDidMount = async ( + editor: editor.IStandaloneCodeEditor, + monaco: Monaco, + ) => { + if (files.length > 1) { + files.forEach((file) => { + const model = monaco.editor.getModel(monaco.Uri.file(file.path)); + if (!isDefined(model)) { + monaco.editor.createModel( + file.content, + file.language, + monaco.Uri.file(file.path), + ); + } + }); + + monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ + ...monaco.languages.typescript.typescriptDefaults.getCompilerOptions(), + moduleResolution: + monaco.languages.typescript.ModuleResolutionKind.NodeJs, + baseUrl: 'file:///src', + paths: { + 'src/*': ['file:///src/*'], + }, + allowSyntheticDefaultImports: true, + esModuleInterop: true, + noEmit: true, + target: monaco.languages.typescript.ScriptTarget.ESNext, + }); + + if (isDefined(environmentVariablesFile)) { + const environmentVariables = dotenv.parse( + environmentVariablesFile.content, + ); + + const environmentDefinition = ` + declare namespace NodeJS { + interface ProcessEnv { + ${Object.keys(environmentVariables) + .map((key) => `${key}: string;`) + .join('\n')} + } + } + + declare const process: { + env: NodeJS.ProcessEnv; + }; + `; + + monaco.languages.typescript.typescriptDefaults.addExtraLib( + environmentDefinition, + 'ts:process-env.d.ts', + ); + } + + await AutoTypings.create(editor, { + monaco, + preloadPackages: true, + onlySpecifiedPackages: true, + versions: availablePackages, + debounceDuration: 0, + }); + } + }; + + const handleEditorValidation = (markers: editor.IMarker[]) => { + for (const marker of markers) { + if (marker.severity === MarkerSeverity.Error) { + setIsCodeValid?.(false); + return; + } + } + setIsCodeValid?.(true); + }; + + return ( + isDefined(currentFile) && + isDefined(availablePackages) && ( + + + + ) + ); +}; diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditorContainer.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditorContainer.tsx new file mode 100644 index 000000000000..4ad8afaee743 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditorContainer.tsx @@ -0,0 +1,11 @@ +import styled from '@emotion/styled'; + +const StyledEditorContainer = styled.div` + border: 1px solid ${({ theme }) => theme.border.color.medium}; + border-top: none; + border-radius: 0 0 ${({ theme }) => theme.border.radius.sm} + ${({ theme }) => theme.border.radius.sm}; +`; + +export const SettingsServerlessFunctionCodeEditorContainer = + StyledEditorContainer; diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab.tsx index 5f8886871359..c1131c1b66f5 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab.tsx +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab.tsx @@ -1,20 +1,23 @@ +import { + File, + SettingsServerlessFunctionCodeEditor, +} from '@/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditor'; +import { SETTINGS_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/settings/serverless-functions/constants/SettingsServerlessFunctionTabListComponentId'; import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { Button } from '@/ui/input/button/components/Button'; -import { CodeEditor, File } from '@/ui/input/code-editor/components/CodeEditor'; import { CoreEditorHeader } from '@/ui/input/code-editor/components/CodeEditorHeader'; import { Section } from '@/ui/layout/section/components/Section'; import { TabList } from '@/ui/layout/tab/components/TabList'; +import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import styled from '@emotion/styled'; import { useNavigate } from 'react-router-dom'; +import { useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; import { H2Title, IconGitCommit, IconPlayerPlay, IconRestore } from 'twenty-ui'; import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount'; -import { SETTINGS_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/settings/serverless-functions/constants/SettingsServerlessFunctionTabListComponentId'; -import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; -import { useRecoilValue } from 'recoil'; const StyledTabList = styled(TabList)` border-bottom: none; @@ -107,7 +110,7 @@ export const SettingsServerlessFunctionCodeEditorTab = ({ rightNodes={[ResetButton, PublishButton, TestButton]} /> {activeTabId && ( - onChange(activeTabId, newCodeValue)} diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab.tsx index b2d54cbc03f9..54a565215d4b 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab.tsx +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab.tsx @@ -2,6 +2,7 @@ import { Section } from '@/ui/layout/section/components/Section'; import { H2Title, IconPlayerPlay } from 'twenty-ui'; import { LightCopyIconButton } from '@/object-record/record-field/components/LightCopyIconButton'; +import { SettingsServerlessFunctionCodeEditorContainer } from '@/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditorContainer'; import { SettingsServerlessFunctionsOutputMetadataInfo } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsOutputMetadataInfo'; import { settingsServerlessFunctionCodeEditorOutputParamsState } from '@/settings/serverless-functions/states/settingsServerlessFunctionCodeEditorOutputParamsState'; import { settingsServerlessFunctionInputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionInputState'; @@ -78,37 +79,30 @@ export const SettingsServerlessFunctionTestTab = ({ />, ]} /> - + + +
]} rightNodes={[]} /> - + + +
diff --git a/packages/twenty-front/src/modules/ui/input/code-editor/components/CodeEditor.tsx b/packages/twenty-front/src/modules/ui/input/code-editor/components/CodeEditor.tsx index 723b04a9f69b..dc846b9c0834 100644 --- a/packages/twenty-front/src/modules/ui/input/code-editor/components/CodeEditor.tsx +++ b/packages/twenty-front/src/modules/ui/input/code-editor/components/CodeEditor.tsx @@ -1,148 +1,51 @@ -import { useGetAvailablePackages } from '@/settings/serverless-functions/hooks/useGetAvailablePackages'; import { codeEditorTheme } from '@/ui/input/code-editor/utils/codeEditorTheme'; import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import Editor, { EditorProps, Monaco } from '@monaco-editor/react'; -import dotenv from 'dotenv'; -import { MarkerSeverity, editor } from 'monaco-editor'; -import { AutoTypings } from 'monaco-editor-auto-typings'; -import { isDefined } from '~/utils/isDefined'; - -const StyledEditor = styled(Editor)` - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-top: none; - border-radius: 0 0 ${({ theme }) => theme.border.radius.sm} - ${({ theme }) => theme.border.radius.sm}; -`; - -export type File = { - language: string; - content: string; - path: string; -}; +import Editor, { EditorProps } from '@monaco-editor/react'; +import { isDefined } from 'twenty-ui'; type CodeEditorProps = Omit & { - currentFilePath: string; - files: File[]; onChange?: (value: string) => void; - setIsCodeValid?: (isCodeValid: boolean) => void; }; export const CodeEditor = ({ - currentFilePath, - files, + value, + language, + onMount, onChange, - setIsCodeValid, + onValidate, height = 450, - options = undefined, + options, }: CodeEditorProps) => { const theme = useTheme(); - const { availablePackages } = useGetAvailablePackages(); - - const currentFile = files.find((file) => file.path === currentFilePath); - const environmentVariablesFile = files.find((file) => file.path === '.env'); - - const handleEditorDidMount = async ( - editor: editor.IStandaloneCodeEditor, - monaco: Monaco, - ) => { - monaco.editor.defineTheme('codeEditorTheme', codeEditorTheme(theme)); - monaco.editor.setTheme('codeEditorTheme'); - - if (files.length > 1) { - files.forEach((file) => { - const model = monaco.editor.getModel(monaco.Uri.file(file.path)); - if (!isDefined(model)) { - monaco.editor.createModel( - file.content, - file.language, - monaco.Uri.file(file.path), - ); + return ( + { + monaco.editor.defineTheme('codeEditorTheme', codeEditorTheme(theme)); + monaco.editor.setTheme('codeEditorTheme'); + + onMount?.(editor, monaco); + }} + onChange={(value) => { + if (isDefined(value)) { + onChange?.(value); } - }); - - monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ - ...monaco.languages.typescript.typescriptDefaults.getCompilerOptions(), - moduleResolution: - monaco.languages.typescript.ModuleResolutionKind.NodeJs, - baseUrl: 'file:///src', - paths: { - 'src/*': ['file:///src/*'], + }} + onValidate={onValidate} + options={{ + overviewRulerLanes: 0, + scrollbar: { + vertical: 'hidden', + horizontal: 'hidden', }, - allowSyntheticDefaultImports: true, - esModuleInterop: true, - noEmit: true, - target: monaco.languages.typescript.ScriptTarget.ESNext, - }); - - if (isDefined(environmentVariablesFile)) { - const environmentVariables = dotenv.parse( - environmentVariablesFile.content, - ); - - const environmentDefinition = ` - declare namespace NodeJS { - interface ProcessEnv { - ${Object.keys(environmentVariables) - .map((key) => `${key}: string;`) - .join('\n')} - } - } - - declare const process: { - env: NodeJS.ProcessEnv; - }; - `; - - monaco.languages.typescript.typescriptDefaults.addExtraLib( - environmentDefinition, - 'ts:process-env.d.ts', - ); - } - - await AutoTypings.create(editor, { - monaco, - preloadPackages: true, - onlySpecifiedPackages: true, - versions: availablePackages, - debounceDuration: 0, - }); - } - }; - - const handleEditorValidation = (markers: editor.IMarker[]) => { - for (const marker of markers) { - if (marker.severity === MarkerSeverity.Error) { - setIsCodeValid?.(false); - return; - } - } - setIsCodeValid?.(true); - }; - - return ( - isDefined(currentFile) && - isDefined(availablePackages) && ( - value && onChange?.(value)} - onValidate={handleEditorValidation} - options={{ - ...options, - overviewRulerLanes: 0, - scrollbar: { - vertical: 'hidden', - horizontal: 'hidden', - }, - minimap: { - enabled: false, - }, - }} - /> - ) + minimap: { + enabled: false, + }, + ...options, + }} + /> ); }; diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx index 3365a170e2a6..6f2c0aa442c9 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx @@ -18,6 +18,8 @@ import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPage import { SingleTabProps, TabList } from '@/ui/layout/tab/components/TabList'; import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import { WorkflowRunOutputVisualizer } from '@/workflow/components/WorkflowRunOutputVisualizer'; +import { WorkflowRunVersionVisualizer } from '@/workflow/components/WorkflowRunVersionVisualizer'; import { WorkflowVersionVisualizer } from '@/workflow/components/WorkflowVersionVisualizer'; import { WorkflowVersionVisualizerEffect } from '@/workflow/components/WorkflowVersionVisualizerEffect'; import { WorkflowVisualizer } from '@/workflow/components/WorkflowVisualizer'; @@ -182,6 +184,14 @@ export const ShowPageSubContainer = ({ /> ); + case 'workflowRunFlow': + return ( + + ); + case 'workflowRunOutput': + return ( + + ); default: return <>; } diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowRunOutputVisualizer.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowRunOutputVisualizer.tsx new file mode 100644 index 000000000000..1a49c030ac60 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowRunOutputVisualizer.tsx @@ -0,0 +1,32 @@ +import { CodeEditor } from '@/ui/input/code-editor/components/CodeEditor'; +import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; +import styled from '@emotion/styled'; +import { isDefined } from 'twenty-ui'; + +const StyledSourceCodeContainer = styled.div` + border: 1px solid ${({ theme }) => theme.border.color.medium}; + border-radius: ${({ theme }) => theme.border.radius.sm}; + margin: ${({ theme }) => theme.spacing(4)}; + overflow: hidden; +`; + +export const WorkflowRunOutputVisualizer = ({ + workflowRunId, +}: { + workflowRunId: string; +}) => { + const workflowRun = useWorkflowRun({ workflowRunId }); + if (!isDefined(workflowRun)) { + return null; + } + + return ( + + + + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowRunVersionVisualizer.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowRunVersionVisualizer.tsx new file mode 100644 index 000000000000..8d8f265c426c --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowRunVersionVisualizer.tsx @@ -0,0 +1,29 @@ +import { WorkflowVersionVisualizer } from '@/workflow/components/WorkflowVersionVisualizer'; +import { WorkflowVersionVisualizerEffect } from '@/workflow/components/WorkflowVersionVisualizerEffect'; +import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; +import { isDefined } from 'twenty-ui'; + +export const WorkflowRunVersionVisualizer = ({ + workflowRunId, +}: { + workflowRunId: string; +}) => { + const workflowRun = useWorkflowRun({ + workflowRunId, + }); + if (!isDefined(workflowRun)) { + return null; + } + + return ( + <> + + + + + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRun.tsx b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRun.tsx new file mode 100644 index 000000000000..9bb6fa5642ed --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRun.tsx @@ -0,0 +1,16 @@ +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; +import { WorkflowRun } from '@/workflow/types/Workflow'; + +export const useWorkflowRun = ({ + workflowRunId, +}: { + workflowRunId: string; +}) => { + const { record } = useFindOneRecord({ + objectNameSingular: CoreObjectNameSingular.WorkflowRun, + objectRecordId: workflowRunId, + }); + + return record; +}; diff --git a/packages/twenty-front/src/modules/workflow/types/Workflow.ts b/packages/twenty-front/src/modules/workflow/types/Workflow.ts index 65b2e9a25a15..70e3ab197020 100644 --- a/packages/twenty-front/src/modules/workflow/types/Workflow.ts +++ b/packages/twenty-front/src/modules/workflow/types/Workflow.ts @@ -84,6 +84,28 @@ export type WorkflowVersion = { __typename: 'WorkflowVersion'; }; +type StepRunOutput = { + id: string; + name: string; + type: string; + outputs: { + attemptCount: number; + result: object | undefined; + error: string | undefined; + }[]; +}; + +export type WorkflowRunOutput = { + steps: Record; +}; + +export type WorkflowRun = { + __typename: 'WorkflowRun'; + id: string; + workflowVersionId: string; + output: WorkflowRunOutput; +}; + export type Workflow = { __typename: 'Workflow'; id: string; diff --git a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts index ffef2fdeda79..5244849f69b1 100644 --- a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts +++ b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts @@ -215,6 +215,7 @@ export { IconTimelineEvent, IconTool, IconTrash, + IconPrinter, IconUnlink, IconUpload, IconUser, From a5b2b3522f6e5664554f403cb4a1c3fdf081b7ff Mon Sep 17 00:00:00 2001 From: Thomas des Francs Date: Mon, 21 Oct 2024 12:25:25 +0200 Subject: [PATCH 29/38] Updated image to correct typo (#7907) Fixes https://github.com/twentyhq/twenty/issues/7899 --- .../user-guide/fields/deactivate-field.png | Bin 152797 -> 186133 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/twenty-website/public/images/user-guide/fields/deactivate-field.png b/packages/twenty-website/public/images/user-guide/fields/deactivate-field.png index 03d263622ae321ed347003152977240d015c8348..4b55672d219766453bb88412a8ff7e385c30bccb 100644 GIT binary patch literal 186133 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È^AK0pvZr-N|- zA=OOuxJ#SYWo4L;W=*c)|6)}!&MoGp#T;gJEX76UTcNs`(>Jx^SIPx9$jZ+|PZcH=q{Z7#6tuMtfW*_M zfYzwE4dJhQ5wTBXrEshOV&i$J8VGcAQt(aM-wt zN27c4CfLe+y0tkWPjNKt#wsJ{R_!c2w|*q(?jD8ADaeI_8}{wGw|Iq;nf(Qy$KIqs zWICT1nRs^5zIA!_ee&zM6?hIgbSq4-9=QciJ4-9U}aEfL2;*qcfC z@A7gUP?VM#tnd!I6sG(4MY)bYLUUjxj3h^4L0eKu3SF8_(45T8~V` z^)Gr_7mpFU(ijfGJ^Jtm0c412;8|dYLnul|1**@}_>S0hS(awYBTK))t-B`+ViB{; zFP`j$I7wYmv|Q1t6zcvVzj-UjX9yQAtoJ*FTx2(1A@+JyyHYtm@VAUc2vA&vhb6kXDr8~0NiK1TY zo5zI$*vO03&BIcgFanSPF-a2l^}?TG6q+K2J&-15 zVYk`3LiVZYxY>Qp!s~;7&YDw88Sc@Ul#8OW(J#@xD|$@}cU$0UfF8-W3w0hqc;pA| zZsiBDLv&en^_Ry8*5lqg7k7}pp&dN<4ZcQ(c=Y?>@8u;W8FiGvH)RslpsX1_0I7f+y1?R z2S4@tae{&}xuH+ogDKFj`PyfJIXbp0o>XYT&%e-*Y=BFf2!5yNyw;<>ApRG7^Lz=p z1F2EdD68`<;V`sbVElfkO6UvQEXMuw1-5LBRrRVA)fLe*RhLthSInzTVkXS+D!`Ir z>|iamL}-B`m&cZGLUW@>8Z249p>M@LxVc+=JF$<%QsN4Z9c|Zp`l^E_AOFF;v%!5q|WVul!< zDWKUdEA#NH=%@*dfUK@!(-1tqR2Oi8#U#a`di3cePuYwUw+E5v<*q>RE> zA)+{0H};Obfh`hO(jV@AC1FyQIXfOhk7PybSn~55E2))1=6=?EOe%2Q;(27K_s;t+ zlq$9efxIH^5k6mOSO;j{I*>fEqR+#V!oPAY{mdz^=@_o28h~5R3&}%1R)?cnj@Ug! zf8R^#W;<0zE6H5yFgi4~v~xK0dTmZKgzx07*qwe-M&#$DR z9GJE;XnMlRZy4!+}(-lO{3Nxy5!aIPl|Z+SBvMYBye4ZO&c z;6cm!i9sWWV)$k)cX4Kb1l@zZKG>I%%JqoC0WoD<4&8^sB#_d99$lqxFkp)OZGul$ zYPjz)V&KCxJclNy3}h+*w(_3v&^7MScR(baL{m&vkIW=?PP_+7l}ZybHlfXE6=D%8#p?$=JG5E{BG^>>)Wsl2Z*x&WPMj^Rh$*cY2cN);+Afny@Q(gF$!@ioY6+N99 zEnxg$$j%Zx?1+Du?Q{9Z+Y2o$@^l#QPyh$V{Qn=o-k}_{#&z^|D-6sX;tc7~Fu6EP z^t5DwZiZ5{B0Jh|vf2JER!S?J3oYnPF2GF1SAJInu0|kgNrm^mdLl`du6v`ywon;@ zX2>!wX8l_^>E@yQ5Z#8l=EoE7q;GJ&sw(wePXZi-_yO9N8d7g%@M1UM==4R_z#+V! zS=3yhPa~-o$WSJ)@TsT^M^b5S#W}kSdAY@MNtXBA&GQ&=JV|d$1%F)0w^r-rhUvrn zFFVg$iK9;D*7tKBaD`$qlrCWzJ@Ik>Q^!o}7t)NkeiTWI?$V!*=QUSd?s1eG`Roz3 zKYjfb^t{n@AjdPJHKV}Lp=<&s71wwhxyCgVr&d0<-Hvt$%!RwjY5TXi?58AagAivaWe&a2WwssbZmw|>}b1GrLC-QMWU`aXx`^E=8-1Hee z(KRK@B7XreT&SzV)<$dC{IwIN3VGyeZhdc-PU75CufWd6r*x<%WoCRl z2-zQ#La!w|{gbjCxvUL~*CTyZ>;Q6$%Kqk@K*Gk+S7GZ929yI70F#vO_4=OllWy5$ z24R;EZ49@SM+AK5I@l}S9$cKGj1uBz5DO{^3M>YtBo%;jfQ0H(0RO}OfJ9GHUx|9y zA>wHoLFzr`pM|JL)aPx>w3B5A<$)lN2nkR0O`T^?6yFS5>K7&KRcIvfXQ7NsJ@O-5 z>=wOS5la{oATX-;=${ld7l-1}#2Ls}kuKufmU{N(Yaz0ukq#XbZ8t;UxZmTU6AZ`r zyC+4*QSQM*nEWrl`+3_;m2cu$haq7^6u)k5!YcG=O>vQ{ZB~K)L%eTnmP#NNhqr*h zKBoox88^n;PFd*unf;#U9lhHG4$-4S9#G{VG6LY89I=QQkC@3d1*#S;)9%@@7U5k$ z2+Q{so`$A{C1IjAX0aY-HxHdyFp1&2;_gNTvr*HMzZU;6x;r{bdY5@9 z{5<|kizU<8hyclUGk`48n&82vPyCA^JJE^=`E)_6BYToJ7>5Bs^3i*s0b}? zk&S!>dPZ^bgp~&}Eaqf^ks7b>I$u-oPu)AzWQV|%8m2yZoKX0_#?!-~zs7>92ow2; z$Jee!9@_~Xf9mh`T~dOm`!)PL>{d+OTa*W1J9E}EpFZ?anT1sXY@gio2z=x+eKEJ7 z7Z5+dgVsGDFCb1{{TFx0XB%*ZaHq^l5JqEF05j5G0Z{D7E&TsbE(co-B2y^Eueg}z zW0?anQ(pjPT+dBD)v^4}H$U_^zkyEjR;#h=0s`it-NZs#^5fEZl=^zSCPcRoSadW~ z_vAa-K3@I%l$<;9KyDY5oULwyU3Yp56a}1_b2^Ln^!E0LKv4~(g!O~i?3&n&T^xR& zim|5HGD@h$1e7_e9X@s|R#eGM-a|1sE4*nyw+7`(p^Q~)=lA)i2uqF&C>Y`FCG(N`mEy-$MLHl)n51D#@@d z^%_zZqGLd+38lBFWhX3LL-#m`(mzFCw47AB+J8y;+~Sy?mv`R=Wh1D4l7F(^#5QL) zxLSwJF9vfPr~eASI-~=M;V!b03i_S-kza}-BE6}A>ZpA0hDMAg6&zZZ@_PYyjes^K zEOg_k<;&Iiultgu@w0+PAxb2*I%I2)?eSO?C`0XXQ4j?d!moE7IU)%!ZHZ3TLA z?i$tSW`IA|rf|C@43)_DpnLd~aVOWDa@URy|64FiVv=F=s5e!$Uy?`sWi~$jiP{L2 z*QW5VvHDVh5?Rv@VBFBNDw7I@(ZwUK#77F!gC{W!>0C5#oufcTKBjl)`br*ny3Re@ zSXrBqPKFR-aLlvcZW(v`swY>U2TKxmNk9i%B>;0oLWY>o{Hj?Lo`}Jyf}I~7ACfA| z<>I?COSe)w1{vd$w_gc*O~&^-DMZZ-g}m&K{qmh$m?Nht8a}H<&7cL?V5YPQySq{MZ0eZsjCP(~W4)BCR;n!Q2%#jp=vc=hHlO*B81`;NY%d zw2j&XZPI$g!Qbf&>bCuDTv>vOxW{<~`k8O3z)}R31Xc>x)gf~H`T=J3S%AU)MXZQi zsC-d8RIBi%6E$MS-PwF6>Pd>bF1-7(b9YY!KGI<}{HIlC?m;~sl=#L*;fiZ19b0l6#4O~;^Z2x|Vm<@>WAx$9 z+j00Zm7F5=W;Etq^&HFTWS75~VkDgf&n7tXHBvI)qvqjM<<*+zh2onjpwm4plZiWO zI&?|DQzeJE=$#`=T6<03jAX~N$F6=rtC=3JMpUPqQFF0}Ag207^NZ$WiSgy}tDlBc zH?;L~Fl4OUy%jC4sam=QyB8v9I+h=nN+I}NBa5pUAy6LHpag<)|B1}hY%cZ(P(qM29YBEpP7>9 zxap?mK9EI-+6d}oU1QNJ`?YNwczW0QlSI6S)k{ptYx+k8K;Lm+s)0qZ=@^Ya5s6X) z#${qkF&DOD}%1tr}$HgV0UlQNfY^r#ms369M zxggF1=UI@rwFyJb_Zm%$8uMhISJ_9iI7KDv`LLvkD`7cfBsGCa{Uu)+MOqp0Xm^yEwBW~#=QX}wFQ3QX<{Og1%IfvX4|dlQjs@GGW)kPi zx32u@O?L|q5w{LKL4igE{Ohn>Mqd1*xzA zm2PtQ-SMkkMmUx7yN1;wvJkr!ZWZi})UhjS2T85Ol;YyK0o>B_wZUy_Bcrinr6|N~ zH2m{!rd1m4)j`UqF#hi~aA24Uxg=lK8v3sIZj4Xt_mdqHY{zjJ1-}rkuxbyRAIv?7 z+;FwCtfA9{=8|g)W9RpsZ8F1?Qm_L7)QK3=p-xnYTQe1Gv1E*WYO$ZL^nCo9UOHaJ zlIMjv%tKcKtE()QF-T_YR?nEj$>_B19J$red+2#GX0VoLc%+7^{9f5^ETzE7juuS8 zr+F;ntoW-dZDfuiokT(f00^A)#ZA)#py#SLa+e&Lsfqds=jh1kuLCTEoooBdo_fus zhp#jY`Q@dn5_707lrb2G;!N*0AIY->XdLhNbCuDU^fpYtmk6f;+cRN%%cZz97EH7F z9Vx(?KM4ZEuo5@lxxS=#+&~3d0m2HPo-8pL5lJ>Zw)UYC!QGs6Cpx-7Z_xm!DN8b; z>=oq~c8)?WY$LFO3r*VBm|33nqPUOao596;$lXf#!HayqkSRN?OiQMhz-xJd8UpD- zw@`(o;`5YRjEXqa{KG_$x%ips+=z6 z2wm^Dq{5+ouN~@Ol2KYonP`{+Gt>)P^s)coqaoH4R$ffMzq*G*pupy6k2jN*UY3L2 z8T~ct9yC6`oljLk5A0Y>nvoyr-%Cr8%N~9Ow-gfZ(|s&dQ2RdxEVqe-c|8$d-c(E{ zRa@)YB)$8i(*$)LMY05qM?7pY%r-QCriyBN!p+#EGL~yuk(`%zB7NS|F!>~ll&eq> z_K|`a-lxFADg&uE+0A1Yh$6tFU^l5m2n_!16_=yq4OcLfj%h-Yu}c@Z5DBIk_LgabbYI9>zOB!YO5>dAv%!XMjLN7+Wia2Q9@ z2{_Eeh&_ur+PeMsMK2Penj*(*@*h0X1o+eFnzjMT~2%SypP8`nYN{qQ9!|Ss=PzxDEF+Ou!By~DFgF7hDaJyn)Ntx#b5f&;iMmo%G@1 zf2rXktw?-biYxHI$#@_7k1xEGtAbg;CsI3W3SfHe<3|L z`0*RjHZ10HQrDm>i`1Rfg<5VjBx|!QC+no2+h$Uu8LnSbfxF|nIxKSS-*RO(bUOoe zo3!WYgpR%gPFpC3;c|m-ts^t+>wwpzW-+s0sKNrnTHYG!f395vbfvony2@VFDFT>` zUP#kt?xYBnAd;A(^vnxni`-8Rc*Nr~mYnlp=)O64Q`ws9q;I8V)x}^Z<8C$zVPIGr z^rQt-ragJSE8rjt-L1eX$DlHrigFud`$Jju$-sWY){IPghw1rv>f&PSVOL|wA}O)^ z*QBj8H|3S0dL0#DNg)HCu-8hV3*H}1zg0zRS@H>V5`&{JDTnELu4%W8IA74F^ERDS z`2LnaCtC>{a3h5(YpfI%R{KNrpg!(9edni*=tkQ7!}AFE+GY=_LZ!S^^i+#l(D~AH zCz9M?#OBAHMpscusixc9z=C+6Fn5P9OaG>uK8u+^_%DB`H0mtNKO5pi$S8ogd4#z$ zDthFX_#fBY%~@=b8fe+bwZ6VBW{W+hfH5z!Ve2mPsx6)Daq_;`qB*&m^I`buttK_f zJtMO$_&ianCb6WN)cw}Yw|CRFQRIZst~&KWy-7zaNSA_m!RyUH3jKo`P_V^qHF?~g z`{=)4%k0qdm^k|E+Owq0 zHA<cC9A*^^nxVHec`8>Q}nrE>KL!DPm`kSfO!XOauHBH zhw~mCV1R*rXdjy)p!mpZ$K0)`pNANP2|@g)IcYoRF#X4gwppOiu;_T1(Oe;3(Y(L_ zzLc;oK@rIMm8*=0Bjb*0Q16*WEr& zJ}q}Rw=|^_ zIBo%=134G6yE_o`C)k>>3+U~%`K3*49-dz%*7OEuSo&2QbF)t7Vvfu9pNeu}ElU1= zv@C0;f3njj$e`v>6-{5^2R^}3I-BvxBRY*1qZ*}jwdbZz^QYsPD~}=e^y9 zxS|ifeE;@f%$;8i(o`L}RNF`^&Mq4<4SS3F0+vKm_Z%cJ>!Zh|HG9pHy7d`7s_C)J zN|UF+&j|GMN8pkIrC^PD;L}r(rofv_sZinbK=v~$+Y;=i%lO#HUNL@fXo*PZxbbh(;`1AkWsgsLWXCSPS} zmlufAwj4xahH_%}12W9yYQC>6j0JgLxm4%ekkoB|PP0%lz2>YPC=ikJxG*o>rVKaj z5ecW=MHW4MWHwnP-5~4Q z8YIdgLmgcbEB9`7i>hiw#&i|_ZxCl{Yidr>5Ua5AKG$_OB*}(Q_x`SFMqdqeX_|eZ zYI_aQ#3(UoMvJ`6bj_fjABKfd3&GN&nFSRo+opP!AZ(@cR(p_h)JGf3Ab>7ZWYyLF z)E(#PSuTS#b8o0LNQzO>6CPoue|0+OyXZUlzcbGPh}#a>FrFgFp}@^~P>76%TN~*L zzt8XXGQivU4)PxvcipV{@mf@soTcBzbV!XJw$S6n*H_%=Im?h+vLB2ZGvI8LdsHGv z0f#H<31$Nz`CJF429K=p-pcWvC(^vYejeR>JCwlt<;wDnJlB<*Bl*i}hC0EA==^kt zxbtIjESZQ&KA?^Ru-90NzSUS!XBSD+d913&zP`nj9YD#BZ<0SGPUjEm@JTD3s73wv zrU1c9qfx?!;s1KVi-Fi;(UBe*1rH+Wm4Oj2d|*0;y(?A!ljc^dvBk`D6MH?Mt-UF! z46wfOEbQ9ZrTZmY$wv7lWqBgu4u@iWkx6pd)VT`?kw0jXymJBBDz>P|oeQk}ySSCq zw^+3cOJ4a|=w?*=opfv%=Ce2PVMkki^_{&(L0iIWv*TxnND7*;;7J1bP=M#pxtU&qRF=I`e7iJXWON z$>p^$q*<;Dl_m@YZAT&F zWzFfb!(G4mz~70gDs_3Fp!q*P4~OXnx`$OZiHO@mcA-!#-(RWe+W(6CO2}{acyWLNKG{Q8CiL+l`~cdz{uUq;u|`Dq5uld`-dC zh{t?%dfoOX4Yzp6-d)ef>yhS4yW_Eo8ygj0*9y2+%iaVukGZTpo+OUy8#|>5Lpw#Q ziG73{tC1Wh#`SKdrWYynr4T2sW}r2%UO4tsoXdN5-b&fX>|DE9H?&Tq{AO2KASkDF z+Zv6K%hmB~$VoHcsHAiS6(te!f_hKvNM5EWC@&G}3P7G&UivOGNya$oc3$O0l} zj8JGdao+7%p-j$dc`p*ZZda_1ldm$_HE6D&511-eF*=#?M0n_`w;qgWi?rq28qdrX zc0>Ok7IFHt1qIN_kJ;I(bn)?DBGeI5#LjXGb?&=0;g4~2OxnuO@k{&tiQ4UX03XTO z-i-~p)%J7KVz)uR4uIr?#K|0Cz9P*-wWWrLPv&(zWSe^@BAJ9)Pr4Vpr!EkM{Km(7 zC2ey`do7tUE4vWD$*`CBfUc}lpH|DmWdVA0JRA)0nnaXRB3O1$pm(JCyN}K+{pO?A z!q2-5l~n~J*orLQ@haTgRfUzpJe`pwpjyX#bbeL832%!m@YO@1k?8J*WYNCVaW^f- z8uq=9J?eL@^Q)u^MzdISpunumPocD$W2V2Y#T_O7Ed8rDa{AixMC*SL5+^@6MxJ|^ z8CzUr(tq?$ztC^!@5dvXJ5N9xTwz`m>G$pY_{Yo0r*cVC;wbs>r1%rD=gxB+1v*PS z>696A{mn2@mzUM6GZ%KDO|BD$AHM{m`)i!188U&GGF2GKmgmFNG#UXGh}udRCr(L& zhihPg-Zd)XZI>`Pd*D+-`L_^kRge$U6G9=U?C4&qraI8Ez5i{+C}T{6+L@$<5;u!( z^}b2rA%>1@S6EnJo}gOYHMJ(y%o5yl)EB3dzfs_rS_R7{B9s+&&A0 zHQx(~V6KC8Z1tM@ArVX>;LGf)6Eh<~V1#QhTMolpC*V1}At2A!dt^}{L(u(PXZM5U zKc290ORD!{01CPqVip?D?SPrnmER)Dsp?BbS+|p_ytzGt*ZH8VzA{~R5CxIO%GVvV zfdeG!Z}vIpx}IWfmwhoW$<)BP6Iy6D32f20+4E3ZpfeH0;P*bwL%2^efG{9$&YC$y z&i@NqxI9YGZmkbV0>ONmWW|g{8-Jq#zHWSKlO`0SankN~Itrz^Hl^6OP?Vbw*s=>^ zGEk-R9kq3!PFC_!ViDt(I7Rkvep|yV>Gj=_>o)x36E>8>jxUlvYK z+};z4w*+PnYHW0_3xluA@a7}9JlLWMOA4EU55pNC58wSNJ`G9N zm|%o1mcPPRa|-bK#^<9F9!!#b*R}H5GnfG(gGY0#7k-^{KT|))^xmRSxYZ1Tl_v_7 z*N7I5w9R1$$7KHjxq`I=*rLZq#sG5ness}z06EHKKhktm_(4~D!DgljodYG+^(LVh`tQX3SYPeRMA^bsNQbA8 zAi2RZCoE1AwU@MilcFm~x$MDsHZPc8ux#woN2HOA&f-%1wH}aD;2HvcE%t&4IzYe2tsAEOU z$3w(IyoFgV(e^Q(9}$4gEV&k&UX;V)naP<=FD{Zct7ALnUFZ<#T+8oCR9d_6K>tLe zEpLLA$({4m{KwXapCy2=*g#HWx{i9rq_!+^kU!VaF^kVlFwn+PTjyX3nY?&Cw*g`1 z)&;!%k`1~-Trx{c7?lX>N3f|QCrvVz+dxN$`5%}piiv!cLeu1ivYV}VP`VzMSVVz! zND$E;L3z=(D*!0)>+?_{sQ+hd2v9EnK6w)oClXDnz&!>PN~Q=n+PSJ~vR1C$>V!Y! z!V>UzzO%JgFNT;_k`eCL!FB{_q)q17Sm7q9GUjk6!`BN1WKL3b@A3O>o=oGQ=iIVw z2J5t&gi$tv)9u{ov_Oth)9#1x;oqBh>ehiJZPq9UFq+4T!KYOq>5AWCOJtpzYFDdZ z+Rbh8lU^f8L%8t>J$d3yV6~Es>!>Yfj)pVKuc~O~@HN}(HrE_8o<@t$!)Cf9!b~uA z+p;NaK~%GiX7otzzIt9p#w&lp==JI&B`d!#`zK32%UEVx91Z>C-U^aeIqlN>WQ#JUJgFoh+yl!miVAG#%aauJfN)J8H+_ts$EyP$ zMa0hu;u9hx!R!2`;!oJeg1N~L5OWLo^Kvp-4cWjP^&@MTy|^bEJYIi3pRrP|`0lkf zYq9p2ZPcOb{BSj(8Gb-XO|s5Ve{X;qu)E>Expa|8I)0|W=;HuTEqM0bEdknb;`=#E z|3Sb--cpGUc%JMv)IBpAwg~_Hyq4-) zzeRJJvIrH9tXiF^EGvg`T0eBZ*+cYQ*~MaQ^(88zY5`lhjEQj27Q_ow0Q&h$Y(-#@ zLe`wRc#mIdIv$?VexxSw<3XX%N_FWVeI z{Kvu1qi*t@a=AbM6u~*1JMVzI0Ezx{(T60R#H>frnIlrG05wY^28sF}v(P}I?Cf$R z<=VZgwl~^pK0F_ixq>jI>(^Bdm?r1W)nX~;qHZfcMvZ5pz2lyuMNj?1SMnCa>($8l zh9uF}{Eb)kv%*CmuX$P=UbB31N%Y(r-qfD)Y81z)`MalRy_W&y_yYc0T@i!X(-)d~ z)WCA1FmkINazPh6?hmdcu#xAllX*?;egZqZK`3u9yNX#7{25)lfd#fu^87wB%eXz8 z%w3ob1gLn^p4lcmr^#l3GYjF*+Sx5$+5g~oFv+wX`~*1!;fxV(Gfcs)NV4+GdIFsN zj$pE&9eemn!eEj-C%LzN-s-enO|dP6Xi7( z?}%X=7O!Wbs9LTu)c^MVCT>|`EvIz$S7JUwtNx8y(L~opL+5@{xW7EOzc%{9alzGM zZruPE3j|m5(h5zy|8D7wi+QCS)E=?lQ(Y9g8(<-E^PTS1>leE82X-<_0bU2!7rZ*hVb*QA&UKT)O&Vh7T-#pmJQyXScO|5Bb4TJ-9M5Zndl_ zpgc(~7ubaI39mQjT<|+Cmg%eIk-aee15|+R0jyeR1Aip(5fMZA@_HYIk@J>Fui%!M zZ@86j`Um)f0xRR924m~q0&OwBL_XzCGivML>*2(095Wgp{`V=hf?F|6xqmeIf4<<= zHveuM-4y|5Af1QLygdBpWi(Vz$9b72(7;(QJl+>zLH#03ho@#5$3|l!N@{6~?y{fRGQr zj$zF%lv|!2Ns3Gq*ecocL9~T5b`~yWsMWt3ClfHXWbk1B^Yh&qg0Y)I?x!#Im8Tt+ zKF7tqleGIBoPOl9xGUiQq+5v_?Ike2M{|Gaz;;=H;?+cGM=g)vx!dM&*JNo!PCPa{ z5EuEkdW#!u4diwNe)PxBD{2-SiCCZwaGS~5BC|B!Gz~7Q%sF&?(}!C@Qvu474DJ-Q zof639t@#F;Nq;cB?@e=Z$Ljm&TXMm@8j#zfGForFyy=|Tec%Hse9pu%TiQtgm*i0k zOu)+Jz@>Tv#m%S<5mZIw7d$<^TsEMIT08swnJ??_GLBw`wFi6P^8VB2#?w31;+oP= zS21Gk7*y|e_!N^jG24+ZcpzMbfoCWZ)lky_Ofp6E6k+n7hkRlX9`vau(5YR?yN#&IsOLwftytV&cS1 zEo=hcXx~Rv>a=Oy(RtQ9D;6k)T<}Hu3<_6%w%43F5!-x!=!#3Hs7v^CES+uR<3 z7Z)nlPM9P;NiOtjxN!RCI0d}h8;Tv`Cd8Rp!8u{kQvz{9+gKm-)L-m>kJtjj{I9dN#MfH|g7#~^h{ylv z+<1+a4@f#?y@!+nZQ3f*vK;5X2aLgG={E7Js`SQv*54bHEWbJk?)tTm zJfL~lRWrKLi|DLvwjK|!Ue_D=)qS{1y?~t|=tYv+;;S^=y+()>eA(Y_RuM5BMAX3S ztuxUW8?dqyHQ;X4ZZW0Pj#!-&xMqTzi@m*kL4{)LBc+rfU}c7I)?SzbPaa2D2D)LA zl+>mbbbt97pok}4UWT%{AJq3bxQr-9bZm+1V-uSA zgR>iDSkn>s{f3HyWaq+k5;!-5W(?4Pl+Xmpv zsF5}cwe_UZAMND)f7Tx|JDc$$=Ii#{O1%|sZH`OTor%B=?z4WOA1UH50dPC=TJZ&> zfJ??wHJ0bUW4N~S^rZT@#N6K2nFj|Vdk{4RAOEh)jzEo7-BGl;C?tQnJmQzyZ5$rp z(IDVA3EH1j2m^Qf7fCc(#tSHCW|O1YEEj;Ue>qBkn)Do4nU?vfvRvF#*EmM-Zhd+9 z;XgAhLDMtSu@V21bva2~b#yX-abgflDz49yAe=;#OJPa>>=Qk1G0!{lkHdH9Q8R@4 zw8&mr_hb7*kXe=9+_12J>&$bQ!ZYpt ze(5VeS5jhEeth~F`lfHM_dH@P0+3;3OCF+^YG41i+2`lE0>aJ@@B2bhX|K3bqZED0 zRkyLo+6$BV%>ARR=i-Q&cbsat^Oc0^HgM~#2iAX-5x5}sFz(pT{j&vC;L?o`}H>dFl6^ zRw(U%B2#m)#XBl|ZCTI5Po$bPyK?dugFs}g?PMbZm5F2f1aOlAN3^yhe zo_7uTQPc6O-1!{r;g+_Ga-wT0%BpMHfkOxntml2;Lu@%x+YnD2rgcvXH-;~Pi?9VYIbF*^JS zDVo-nB(eWzpYYqi;6)kV7I8TJdE2HaR_MRllH5BZ?*#XbKG&Dh_!ejMD|A%d$srhZ zID7tr@R?&*)|8z@#Z;Cn%_UlO3%}qm-`V-Q7J0(Iz2azrn5Q6HO#h3nmc=QRCWBL_ z>Z6YzBX;lCl3*8O*~MCJQp!k99V&V^hs??$zGxGgj|U0!@ZZ{APo$AEBFOum375IY zrJyF)i5Z74fm40g!2R!cKF|(&?EaYbvx%NK1>S#A(Sx+zO{$Qcg2evg#k<@|h>5H_ zH%3IJ{N>2~OyxO7xwL-A2g|9TX0EvCMLV%mT3Ot#evwMsn@5s@6aomkxu{>>qtBw) z!w{p~v54u$?EEvl-!Mq-+WtWCl*D(x$d{&RO;V!VOcM0srjKg+aEc|{<1x|gGyrT} z1j6sAy<>5a>tYEFtiy`cp!>g?soC@3dv}pohhn)s>id|{ zfyQO1Cj9kyS|GSG9=pN{Uo{FUZ~Nj%>%c=4jc6Cw53o!97*f><5?in#lj3h!T0pK?qz&5&^}ay9h~i-!+mg3R4jpZkk^|E07L!GC}?|0Fa1Rt7Vz>PL151D&y$M-WSS6@pQqvzBB3gr{@6918l?62w+!HSk=`Lurl1{dkL`fa^Bo$XR+hupKUTQ=88l|mls24dkp4;Oo8u9c4K`2S4;8Vh#?MeDQNBM3|)GKn#TSnk+ zTwuLdmxjq=s(6_oB_8u?Gnu@btUN8f+e>E~01ISMMKfjt37$J#yLP<$)qUD7y7@t? zR{8O*qk=_EM^)4YeujR^y+gWwux-Bg@XHI8;)J$#q0wiYmk9obIIwY6%sTMvy~4v+ z)H`M?|46vTxS34Gh<;?gGjP{#W}%GrKesBpY&qrpOnOJTn(ilkUdluN|ET)za5&rM zZEJOlRl6C@U*S*q(%B#t&uJLDg_#qGV z%zS)ju|!A}t~8(r&S#)YR@r10J9#ISXw9Twt6#OZOq`iVo$xKxrXbT>XBLtW{OR#h zb@u5Y*U`jjyvq+)IvUaw5EAhxkCx1t0)wy@KZzR>oJ{T++26)a6s=51EKPIO9leI# zimzQ@4qfU8uPnpt%9Z_QJ%{Uvm3a5t0%kOlXGawLC(1Yv7w>^**O~l=nWzGQAr|$* z!JG&YEw%VprHI#}<$-@VMLwL)eKMM3`>kP)q)ap8e&iHUCJjs!3T9$fxbd;lIU48I zMkSs(6}ZN%O<+|Yy?d6uTd&-c2`Z3Iflj^2eI_0fd;1ra7^^EPimuo=Vxf&CFgF3& z#)2tVpZ-Hb!F@bZE>b>BaOOVwnb3vt>7O=&ry`mas{P6Ou&oCzN6S``n#8?#M0+^} zVPX=p%fub9-nZwq=p*e&B+bpHxzhpu7AFUh8KqzE1cP*|oYJ6+TUe91BNLV-g1|0N z43Srp(q4AQ7#|26#w?#(4ri7xuV%>6J7?=8PL2u!fi!Ge_(0sD9eqMBa>oovAcCkr zi+3AJ3tD5__3DaB1d%ZOq6I6FA+-GdJQXKl5)IDvEvVKJ3t&@=CEo8Z z&i#9EmUbgr#Yn$T4_E^+rUY+H4zB`Dv#+&aNrEaFDVAs&H`Uzm7nM7Um(BiOmKX9; z7;S)I+%oT49_3Ie9L&n*0_xnWDEMZ6^YpZ1f2OH`cHUvA5oYXvGd#-dyols3KZ-@{ zEV@bAu{CB-dV^bkmSX3ix@BM>0{3h%Bj&Q40!+4q~5}o(8myrwQ*&xVD_k zfa7V4;GYgk${G$Oj71^QyxUjZWbV_OpGb}AVWMqTEc8(yhtOU}><+k&nV8_N2 zjE^{d*PiTX$vJEQZ7De&FgDwA$?W_dIrs~ z!K^kOLy15mX->1>@84k#eI3^E4g}Pl>d#Pz$QnRQ&p&-KZ*L57BXa0I!rB3w;P0MrQqzgbeny(&mE@W}YWI4~;>EGR9Cb zuSb{*oDKuCX(lz;ZfJ=rqs!-G0j$uj4CwcrjHdi3z6iq*B+HH`@{R~sLsFoM{qxub zoAlh%BZ?OpB{V#{vjHDA1?JT)`fzC1B;?n5anVmP1(Fd~WzkE{(S@`v8UgPu)%#bX z%+9c{Yak4N+89o>f6kS2PhXYP(q!n1YM%nf;*!IVUtQBf4I|LZ!M&@Fg^D05&N3Ij z=d340+2V8O&GGHZk`Gt?noY;4&9LxNF9|%eM&GPbUz^{?XvDqdHPn{57p90>Y@Bxt z{7PfjcTHL=WxHnge&2ld>+&S>ThSR;_b8oq^fsbi%_q{frnFR68(EyS)dffG9=CX6 zD~(1*)S_V~dp;b`J_d=ot_@LA=%)zSs`a7;B3w>U zlH7hB6y0$qT111#MuJ7n^zx4$FjIoQU8)h|Cg$oVR5$Ovr_hwhWzo-BeUCMs=)|(0 z6U$MODeT+E;utgN>>brvq7xWHNHg!u7MOxHT} z%%*$RU57J>RhR`r!W?~{LA_)R&x=TFXXAJh;~IJ9-RO~{7m~~`08edEXkIUBL~zNXp1^# z#rZdMU0jnl^d#`R51-X-fpx>HRhKJUE15thG6bg~N#CaVzz=St#czj3loPo2K=z5? zG7rf?DIdogS;}yx*YS&f7joxRirRo9tYHaFMfn%yPNa zA}dms>B?z}Y-tOeU<&^HPA_u@_;VNI&)w35u9>lZWadMdJ3R4J;jz~-(_sN27LNTz zfVdt`xIe+>p#!3ITIOv?ge9RYUzceK^8=aT{wHq&#AU)$YkN`B`olC@40YotB$&Gd zOL<8xt!Ov>6pGx(m4O?9R8m0D{(2|}wYK<#o3yL%#4B#efz?IH4S%*wi;s$@;@$Wq zVC2~*NSdKFw9@$Uephds#OZ0&aHrtqZ%U&Z6yd4e2R64|k{Ml%2>0nRFS+DJPkajY`d@NuJ=cjX1EQ?pTUAf!b zGSV;Pf4WPPl0ccI0BDoJmF&UA-mMto^t|i6UNFkIRC_516>Co2m-ff0l2f29Pd5Xs zTkX~e-AZ^wtRVerqeIG}N;+W-A>Sr1!h50p>5^#ddz_QZkG&MBrO8zilC*_|Kitm; z%dY0bEFeuO2Pe+VE^G4>)5~o5A-DATtY8|;^qCrRFaHi(T)3w+IMV>S2@a=$DIx&$ zI&(`-!<$T#AiR{s`x#|qwxB~t_BC1=g<16R1oC^@UfcdYavGmqq53%gvHvUbVv~0U zBdC*hhx?J%;nXhk*g0no{F-x>VfL-vh$?D^P5qJHa-MfL`ekXYLG5R0ejTXS<`;py zl%=V$_qV8YHl2rA#LTPTz6+M%B9n136{>qIko6yILM9+pP6(J#8Rpsurzm8iAzARF*n0(%}*YFKH!{@#jm zaAFoPb$4)ZNfy?Y17PPcODCEiK%uLi#V7d;lS(JE^XHMN!BRf@pP?*7Ie_u%m(I`b z$E=xgDRuV-?ky3+y;^SVkaqrrMO)GRHW=Y;ohJ5%Md!4bvY4JYy&G}xIlo7=NWQM;t$wn`;MuA}wL*Zb~9oXW+OgH5jr~ad_>z zbZFx2_!tHI6MtR5_9p(gMv>V?-8~`XpW*eup@gm3B zHtC>JQV)*hyR4#NH%)poP$?T(sMF9iom!K zl~oJmPF@!q2w1EbiE4jP;*zmpL?o}LnKaN;+?3Jwb%_>dC4f;uOlutG%DuRSCg%O8 z1gwqUz4yrp4loP2JmQ_!Fa1_v#J7`fBKHUUR`C}&MWw1C(4s%3lMYZoMY_qV!}iR(QxtYV$Wg#t*y{fjYzvXv%h!dO3}TwO>!FZ;$J=b1l_$ph#O_ z&|!HNvX+c1l#@E{eJhL2TB0RR-2b8#3)}}S^EuKPh)TD{h|*-}l8@Lbpdo%w**=-xtmK zdp*e!>c;NtX(02Hz3^pnP8Wf+AWz2Yx37QAe7wBO*Vrs2!Y=c|nz`6#w@0+b-T&%} z3v#cSNa!Ux(uM>EQwDYkyI$R{{+-PNd@Y32(!`vw{t=&ee%Q%Qq3VhkCoQ(mDtn>d7d^JMh;}{$n+jB45<^pZL!46~TA|W@Iz@reUL8E}8!l%Us>> zeWjY>U!(|ZP^_Z0nen;nqt9x=bQc3I{s-%l+6h+bH$_>|{Ae?p5ydHeQ;M$bB1&!u zDDjK!8+B+piza<6eK8dYU39`O&;*=X<9f9G-H(t$ z#;^kOb+u6lPYr|-9zYE45ksp55v-i1EwrVydk^_wJfdoQo|(%8MUZzY3GHCNQvesE zvneJHh)Y0QTQ*6CK63zm|IOHcL2SWhX{D%XBP7m^qBR!PNtoJJelRB2Sgtc~%BW=} zaco$(x#+evSx$rgf^~`SwQlJu^IvX>3dZ*}+fKT-a)va71FVLY#g(#`v!0D??C@zK zXiQe>#(uTPYc{j04i!mODuSVGjqG;>8xgosY6~cGr>{TKiz0~(^@fR>F zg`XNW!hN5RLB+#hqTY+Y(WGQL6%EhcxZmu!bF!$6=v)X-Wv+g08in@q400{24SvxI z-wM;2w*wL|k83O-UkpkqyX47jTBr$2E4`z24SsP zPDNHtG`1ci1kF0LnXrn6y%}UAcYmbfwuXTtIUB$*bEaTWbo|wNye@pMJ^bAhsQbZ` zJjWi840Bmh@98sZ2^3~ZK0^ZPi2}6~Cb>|ScJ)T$adfH=0c<%P?tRgMMd?vxtfXK+ zr{AvZN|_82Z#^*mE%}&$m_R)20#;mivUl%q9%rH8GjttSGrr=mc=4ubMW3077?;-S zb5~p5%x}BRlv(ci&TWqq8>F%Jb@_VWTXBR3(rzeba}HVRpS?k7D8>F!F)uKcgox zJ`H4U9|Ea=r=WXZefOV^fz%wn%R!kMUfLNYq>7JtJ*3~Q{a7sk1DjL}l8(K2f*8L& zLc;p2Y3!%yG}wC1*zh=O#9cSBOI2Mhk6>df+a}iHQTZOYH%71d{P%AX2p`^U$I%Qo z6-!4to%TH5CgwGjPnG80>%b?hrktElI=KY_4axb#e>44Q>)o%ZZ7i|(vS+p;dV3$n zm>>?hfBJIcMB9*S+d1}*u`Vt~Q1vJ&6=l678H@wvC(nYD!QmVSSBZKNP)nBiZSx^o z86^NhW{S(Us*sBTux)gA(2|9HkXvhT`ck?+g<+hp|7NYfqsPV5obz7>rfmIbc3q-C zl<>$T7u5`$J)*u#;{H~{LZQ`v)6C256Qd#|QBcLqTe;oM%IO@aw>R`fAUuhR*F;-W z(<%l*Xp6cp9SkSv6c-Wws92g9&O|24t+2NkgJn*hD%+}gkui+`jD&&$9Vy*L6GY1tjU%*Q3IRD03YqNt91=*&hE*fz+ z5tMKwl^wHh*|190>pJz_(xu#$ZU*NQ;<6vcq}Joq={EuC96zI+o`NVMsl|2r7<<{|&XhK+S^AG8XG(Ipwu z1i8|-8mq~a{i6HL_m|^$8y}%SA4wC(N!HAyy2R}XX zylqrt{{oW8&KdBd^ecv%HFR1=0Ty@7f+VNk74$%clr28x_2T(U6BpZ4g|pmH5pyAX zkPlhgenqMqyT`fm-kq-(61qNfUE0`Y3E&WAmdR{Z)L;8A5`LY2%!H%`V-Q@RW z;~{f@QLVF^P-&KMAc5A7RwLvo!3%shrm>WP)doB|a$vf4(l!02ac%!(b?s`D|FM6> z;+ctR?+c^Hr(dx^nSOSd01q3 z1!R#nd%dx)zGTstAn?dG&YXZb4*VSqEAl@gg=Z$aRqf{45${+%652O>`QviFT|213 zXVVc5alwr7@=m6U%C1bMJ3X{8ac029rYrwu>QKa2CYvBgUH^U@jMA@Z8? z^5HTIz9qzUfP}dR(z<#XCRjRS=xmqwJjF<+C}rLzu>ZL>9#^^8{GRFP50#Tn;|&+S zRf4Hc1y&U*c{tI+OG>UW(rg>7Yv3MueiHluA#)eYBEylpjNfd&+I$xXwSezTBczE|MeIvh@{L%xfqM@#*JOA#X*5hfEPx$a?Sqzd z7=M96cCj)F0#L7#c>~IjSY*je0RA#VM#sgL^=k%k+~z>Y5Q9aK3rA$88)d!^E@8EvG;vi zz;D^)t-223itjJM2;R>4p7HDgA0J~~<2etrltLOFi9f@2M?JXwkh)8}pU_2*Ph1)K zLmwFXjqH}uqGZC&}PLR$4m!;Coo+^^FNMpE_h95uHBQu z?gNaN__KHtKRr>#GRj#DUdi;(YplEs2W3BrHO zO+&~xQh`7*D`0O6;=<-0t_0F?^hJU`*;GjXRFCU`-3~es{2Vp>ggneq(OXRP`q4|z zcz3P))%qC=Fn*_g%l>u7-$jB0Vmw)XZ=-I6PS60?Wzpby9uf_?g?Atux$N6k7!JT3 zoMeK63T|P@vKxiu(WjOgPi$5cy~})8_(w$+Y#?wuU24&A^v^{qPPNUy_+O_Lu?qB; z`mrx@cU5vN;M3Kq(1{W|0>mM@waRHM^S)uqI+ z39isK#Wq;2T$wZnocYuedx_IT#<=+XzQ*e?;dCy^&RNH#Z`m6|EeK@EN7N$&T5T>* zBWU79AI@TOAHP6yV2+6W2Tta|uFueZ{Jok^zk z8(u(um6?Dco;l=G)PL}fX6_H%qQ1upuXySik7ZjZFZ+bM=bM(ZGO{>79;rW`@UkE0 z90MOd`46UdD{ty#_cU%-Ej7c0zql~=uspFcr?%?Q@R9CXLCFO$m26ML<2z@x3!NbD z_efiT?eCjL6n(wv%*wW11e4baf46ZR>|>`ffwc8FuZ6ySeK6}GbCsMCK^sBxcEL)t zH<%dZDKbrh>qM@;Pwe<4#7!1l;*pJD<7>?;D1*U_%VS`+Bb7H|LN;DfcHL7*H}Y9U zdxc1a6UIz4lv-t=ikr+)ktv$O`P4BF3w);UumMCE5*4VIHTtKKVJA6-zn3{$G+)eI z%4_6Z_N&E5grD1c0=Wn~DUt;Z-%@O}iV|gWSdoy)i0-jQaJ7$|&#WP8g)2`BsuISU z&-L&x?zzCUK95BJs=d~9+(FtlJ?DCH*IOn;CWj3X&P=oFy1Ctk{Z{)@?gvBFtl80+ zJ992sCj{C5O4S(hG}kJ?c?+De?c%_i6R=VLCHnS}@R8R9{Ke*r;$j{{AV3M!BSkzd zKeq%ELcD!xG>+&yetiLLFNc>&rZwJ7`>r&jHp2w_Ssuz*3OXqqgDy-TeD-a*{9dq? zFw}U$IzCzN7;iN(lN-2JM7(4*N~$AjHyi-Yha5O+TQt8VEklG5Z3_X}1Yn9v)7YTKTcl(+uEy{OUW>OFHm%r&?ZQ6T zEbg3ZMYI8#VEy<5lpdQC>f4~m8V4*~>vCo9xHQ|%jyc+Zf*pU_MZngPXf$nNNSU1euP|Evg)gBsAkdQ{utiE zL}9Jeujqu4R>y+pQUFvz6$2{C@$ixq$?urM`2@I3q@<8Ue05mxVwM5mAt~*ji(sX0 zv7mg~pUAHS8# z-|FM0BMOk&6$ew4y{YLu%lM8AJ!_Cv^bJ*#V)tRW62)MRRYGl=(n$AtE5lpn$W=Z0m}ainb#xwy5@N*5Jr zD>vAS5xC04OsW4t`CaENs^W#9q$jk0;k+Mq7OqdkJY@k}GgTXU^BYdR4MVdCi)@-F z$B9Q4CvKLxEYVB?ZU7L^wt0`5XrQ@R8eteE@Y{}(Xy*#RYhG3IB%gR#H57;0`Qom% z%?5Z|Sk0igN8gjIfg$0A!?eF5;6^BNIDp*o{awt3`MPlm)+t zM@t7ghx!5&wdzHH333SngQ^VlH*wDWhW2CKJlB_!%+)!Gx>bxrbv3|^ryX!iyW!6# zN`SloHf+1rMf)vX65C)mfyC6N!-BuG+gZSvNw{9O=J;Ws$Py*vhWsY4?VHzi{~o7m z(`ed#J0PNe8W@jv@D)gbC~5B(6-LMz@kChb{ZKS~SV8J#6#?{2iyLE+?o^a1R=4}X zFCc;Y3JGqa@dAelkAvHPsHJzQtdguyaoWycn-7G^RDie`KQ?!6lo43?SBuc6r-0`Z zN1gvJYqI88e2c<{!Ds5)0kP>b_Oo`$)EAX9hpPtcakej-pMBQyJ=8xT$nT=6RYRt_ z?aFp}5`((|=%%!)s7w~tw5|~s%OT=x+-ryThVA?~@xlq$Qnhhg6VXZ&H2lIJHD8V2 zB9MCZb#i&XB6r=Y`N3SrN_i7YgNIk3a<=#?PwUB_XG98fq=tf??+db+pT`JjKOUHJ zH~8?Mm4252c4J0CDfR{dKojA0Ui7!$;0NrGO2}6pboujaX>x>A527eQk$g;HZ5F{C z*>t#Z`dNwvJS0Z2OT#SJes=*&C&9ekarPk)0Sdvqk_FG0|0cOp0%qB@E^z&!LeHUwmiFJ!pmgEv{@#jL; z77YLSD#b`o*PRbmaHuOju@!qYL=C+1ThPK%lNOsx8%{|hB+3sh1Bt0fW5;l|ZdiBO zHb-xN8BXsbsDwIAm^*OtlOM?@#Yyb#YN6*De!4)(Uw?3#gR@Dh?hR>VUgOH*M7a5yBCOhYKZ- z@UXt9!~O&qaz60u%B4T28=;o*_1K>)xYA~W3b}Uw#16|&f79!fI042mn(l3->!%Vw zEs^(>4HLTUTdXmx=?{kEghAHgcNic3cj3@Y0t`Erq($HlDIcTSCu0U6t4<^wTVBkO zZKJpaMnu-*2M()*UdgYWhrxXpMEnH&Mf24jIYF6~Qj|y%!n%un5fk-noAG-NXRju~ z%8U>G`(S;zK0iL(C@wXwB}oKJ)B+^5j%hXHxLQfc76t04qg~4Ke}0R_U3AAP48&i#}LM zUkEis@TI&uFR2I*tqJNP##^Ut7-7NqXP=|LEwyeYaW!_Dd`D7g}c>>`7l7 z!!Y#9C))pd09R+w-D@P__N~p#>=Oiu9jqZA6!nLzE83AEBE+3UUR z4_>X+Vwv36n{4X-xiFr7pkeZL_@907S0?SRDtlH7=8(TRU{5+1!+s@gL?NextCl=g z-a9|L9PU+i;*@gU0@|oSILKydw77YcNbtHMai@64FHHYl%EYyFH*h%d=$yBolRDhU zaOXuo-xHR(^rLP;D$Zm4#|ZX@<@2p~9g>r(w!a^i0pnrTzH3wxtYJqA@@Z)Ot_zk_Y0PDJW`Q_m!hB~Jq&b`m_QX^EJ!A~`x1RjEvs>UY zqOVj&OH>-)eWROE{om_?3S;VMneS?nZhDs567&$};$WQj8`cdQcNjt*QUR>U--eW_ z%<_hMhK`2U1#S$H|CC-;tA6!-TXOiS|C|pF{rAK8tUz4`XG8RR&eL68=9eNIPe=O3 ziswZi$jyyd5S*z5&G{kwVZS`WzUVr*Y=cIo$SSm~Z9aGmJVi;Jp7!h0A^pqI!^L%jWu&{@a=XzlNwLovp#rTx%%EQTWD-!PHcS}M21JhpE7Sgu) zeSd?>>$l+4Vp zTaEZu{?;h`pMn6EAN9m2*N5bt)Rx7|T!zoNol5QR*jz}Uu$P9!3OSbg1SP4M4=)10 za>amJ@g)S4ZjObWr`j5;J;EIn`gC_ODIn$l*$oyhZv|E>$7@yQx(>T0>7ME!w_q>{ zUsNIhN_+lv*eDU`mIHHT!cvT2do$|QWzvhFMI^>n+~C#A^F zlMc)8Y=bda3tWt*{AsfmW!jIQ274p_bwmGIa-_2bo3rgiq-CIWm&zKpNisQQ;zP6v zi;xQ?y21YVvBUSnl%cj>OWd0A!5|gqkNsy8VMPg-Cn_;d5)Oo2ptvkS_rjKZm4AQ# zG3e=X###ss{Q_?V%S6|j?Yqg#Ccn(Ooi+hwsnxH2TECyXl@+NiJ#Gcxe4*`l^GB0Y zqr^-5;eA~U4<-JQ{0iuQ^;0g)ol!p6W!r!m{gyF+67b&qqj9u(w4`zX;X;Jg14x3&aD&_aljp~>qQ0l$?czDIh>P=Awx`{p|Ksx73%m;CfC908 zN;&4)`AgFi7PbIGVBX5uc+1g?pux542ne%0W1cNlod7i%e#gpxLipIoq4D0o^$JaG z&87-$gJ3K5HGAk=wVY1+)EySRHEXtDJ0O%Y`d5P^N5yioxh{Xz*4`T&Fe=Pl*T6q< zxXs5itx$E@`dbeXiZ`Y#pR`ay5h`;f}XS{-&YV4d$8yl_kB?hY{ z2391|d|1iyf^sjTJ-L7HgFNcdImF>lrMBllgwvCxS8OM^Vd8g@ur7{y$)>t=uPu%u z&~tS)wn|VWP#{v=UnnuL{TL^~fyocW=PUF(|M!Uh{|j={Ex#5VhzwR1{(#&^Iy~T* zUQ0#w>Qd09CJ|fBg^T_m8f!`vG`eO$nJ>Sg!^w^e`uB$@GZSHIp1+p3+D~g5V-a)W z*mUkv+WEGd3nIluK!;)7r;U&p*eE-$~tV@yNw4fX!7bN>3!Sn`2LaD@HA1AoG)mm64&x^g_ z;0&0Q@xSM;h(1Z*VKIs*#aV8VHong3Ifq=mtVp)d#g7<{zFf~F##R=whai_c&UJrj z!-zpr%~a^WZBd!p=Z*daji`Hh_V2||89?G0G&KYAi>b{?AFTosNV^GRke=2mP?u9a zWR%xZ1nPga6eDh!1_}-NXe0o=8t5Xo@N=qZe?NZmFk(8V55j5s^)7Iy;EzeFRbf1p z5%n$adruDVSN~5;k+8UJ3n^XESLH3i@l{rmR5&xkv#zy1drKdVwFZ@} zvblzz7@*jgrBK+O??8I$|1705>Qzm+83kqYq`N-iDni`y^qSwrL%Al%@m$L9%7Qw9 zM;mK}q76hTW>uQ+QEW|#2mabi3oS37PkOrxz#8=awHPwtxSWKYMufgxpOhg7G%G%K z|I6^CyD=@yNZ^vc47I=PD;g6i@~t2YD=Z~*CC#4B#yiV#mw_OwosffEJ6%rO~0{+Q=*Z5<^Gc2j(9MB=|geHe5D7t+u(*F3BO1B z``ztQK`l#7J`oECIUPTiINQ?+rJ6m)soU<4b6hst0@3EA>y{0NM|yxL7}N!-u;R{F z{e(NBUnwl#21qkZ6l+0vp^J%Q2hq1%?F8;A*A8@`hxR#aj&qH|q2L9qWKC?K#6MaZ z>sS~rT3ADPI$b~)iwUpw03pE@n#_InQ5%-*t3oJLRA~0jtJ0rE=Yea!5dV0>+z@+d zqm6E#Kv#B+#En#qu5N;nNGHi+U5A>-KGcb{?RZAo64I{LZ#?DywJA$k^yboNzGdGn$TI|8e-*|&HAcB@?THLQ9hEp*Tc{;(aZ^3J{*b9&Cz@OFK zMvkL{CXCGcUf6K4jFm%lJ;#5Jl2uUVg-?p^sM-2P8RzD?BTw!iasp~S@>eSVvE)qC ziBnJr5aZgPakz=qABS6o%-iA5Ct$(bT9*ZX-?TlyQmnrbaP(Wx?6cBp)E27!T37#< zD3HjpY+l69hcf<*OqzbRkr6B%GUZUHF6K3*T~9RHXvfgh$M!*VZ-U>+idB9Dvw{Tt zU#de_>e*h%6RfLp-1erKTIURvc#r<+wqzA=1LlA!>@=?Fivbbn9n+lax0f5m$yj7! z46};ms2wsuor|sl!u44pWp-XmT8{mc9rNBb6WqssEN|Nive{|BS6AEa*{M%h<-gLj zK8v0yhR{=ph6^z<5NrLln??K(<_E#F?(;X8%`_jl%e(mjJstU?*vK;}l3%aR9xh7H z(%%2dH(`ET-+$#V}#?teSq+?eSh3^Nv;c~NLIms zE~f;;1J@$jX}FFuWHhZU>5m566@fAl$`~BBNrUQqBw4JI%v02MA;FpGEdliTiSiN)_<{ zz2ZM1NTrqN)WW43x+NCc8sw^vC9GIpS4+P8QJZX-lv36PDOYLC&RMxDVjv;dEXTh| zOp-%r@j(p3=c_k%%oPTGyo;v4sy8!$EokfeeSJuE-*G6|!Rx+LAuOT({)1BGtG?f! z3ZTJDkRBh|jiT#>n?Nw~q6s&wCq2(rK-H{D=h+u(Q@zTg%8=kPX}YJK#Gcy#)A8wBVzU4-oq$L`yWzyT zm=z_3oR}ZGcR<$CY2VjH9_9UfuET6JUhw&WMTHj|<&C0N!P=P-zJI z&krysO|{6sRqg-ys~daymy!z820Mz8X@$c_pkZyoNN65hhHDnG;}o!BgCJt`aaYDb z{Idi%`>K`99yn*V<8E-%Nuz2XsYhEjC3~tn!PBKj9Cvn%P&6W=^^!$r0{4x7XB<12}3tuOgWgZg@I% z`<+SEY6R}FbD?>Md(P1=wYq8zRTLKGgL3$bRgWCp%sT!rhoPj4)a!I1B7@~+oyEm%9PYCdaKzP2~pHZiF;9 z8c7IL{cxAyV?^ALcIqL?LcVn(9Si6C^}Bj&z1xZ^VaaMrv9I?5H0!}c(TIN|^vR15 z9!yjdk%0R=Va&e2Q^ZeEe&`ehAz9$5+eSg^XGsL-Yk5|MGyx}4TB4OTa@J@ztxmwe zr5QKryCmkI9?a-@ZphX3jf6qk+|7RgT%}9p)h~6(0@- zdo^E1qn6!5k3q@8%a|sqqhC)m9;^aY=1*{hcG*Z)SaHmRfB2=- z^Qc>&s?aU34dHLGH9R8m5lHJPN!2{{%bHA&GR@Y9WSoeX)5W1de9OA2`)gK%dktz5 zQB9mxGM(FmJ4o%XAVot@9*GDL7{i&u$5w`4&Z}kW7ja-2e#QHsLvF%;)Wz4eL~@^a+J0hc zJZ1`$-u3gV-=raUZ4Cm&?k)#FewiV-_B%lboQhHZ@L@2La_i*((?8gr@W< zq(sw0MWn=`v6{c+e>@6{Xu&VP(|Y*;%5e^aH0>`yZO5u|=fjUkd}dgLra4-}m|NU9 zDn$O4^5P^9T+uFXDdDJc!H_w&RAYB_z_D3+28p*Y;YY)Nx?LcYq?F^-E>2@<2IC7` zmT<4;TmrylM}E$RE~e+3jsrtii;FCooG)hZ$>n=9OyUl8!ZojDuK2Fr5df)Uh?6#% zXBdiu#OX;FtA}RQL*;jClaC#vh8ktX_8&+7>CVFyex3 z6_tM5AqDnfUss{rG!eUQ0!4`@pA#z>k)Iq^AnZ&zXz3o3?p8W*~L-=bVMU0^p- zi&QvNyLz9nTYxXDaNqQ{fUTESqLWcTqKajArSR8^fW!_$uTpue{9}4D1*oD>G!s|T zU+2coI7T6Vaf$}2k6#%C%x;>F-%@H`e9J$DuP7n<3qmoQUJyW;5O|Jbxr~>!YhAQ( z`w`ct&A$7F9yq2kRYi0TzQx<<^|hqxHjT9sj^yzOXdX)>dl8?nP{GYrp^*#=Oi~^$ zYAutS=vQcip$$9%lA~l3c{R)sc)JzDQE)WuPHnd$t5E5km&x7tHY_q&$|NI=Je$5V z&qpKoQplCL8{h~)E$`O@^+&2X3j;dzWlUA5;u)anN6F0Jb6hbGs@MIsrQc|xD00c) zrsRkY6fak~pz!yU7b-8hT3403&OCo+^KJl0Oo(WVnDnl(3J#@2ZE(>f++KPBeM-LV z!5}>t(P_C$)8yskGk9WQlWHQXjG(zmNa_U-ixHXUX_fF#Kxg?_P z-j6gl`W4iKF47Y5{B=-2gDO|a;86DAME_|mH@6-uSw(^ z{dOBA=C0B$AMr9~RNdtS6CL53?`8nB9M#3{<8)ZBRoN;!C}CACD5D4o?XFb*!>CKy z3`bn;#mD!uzWS*!kZzaFJVq%@Y|2wNC!e|S)7VSF_ck)q92X65s=IVr5=r@J@@4#w zQbxS&@x*JtZ8sxX`)R+E+3~A*?*xA0qnLM3|MI7PQrA== zzKfXxtYdBqig)aJH4ku|{_#?OzL;JD!so)V%a-9TOU`7eCG3?LDp(n?Bwu^rLC|O2 zT_Bg(ZK#I-@q5SoPaEAI_o~7wB|bO*xVDn*Bq!&0qB2Nd?Z-Dnd${R0H_<>trfGop zy)64sIE7E9vhd?>9|w`T99~-dSRk)zMjc7=txyPSA2+!a*OHIwFgknhME`i#wItyx zGeLp_NqjED|Ms39LwJ&NwZCpzD9QV@Dv(fq`5kC^h2b@H(!(p0G-_fGMLqgrz#DzI1BVC|se-()5x^ZLVx zIlCDSlWoB9BMahrNn@62p@KIovQoJ!ylVv8DIa&fG*9QT?5fKS`_n2s(Nul~6mxL! zSe>kxUvyEPz-P1`T02)=D$Fa$e!n5{C&-Hy=>6@`MPUJM4JB>4eb0pfYljqx$ zpJ<^xs;vD2RXki-l{4aqV#V|=mEg}ExM_*PUoI1!#nQYC1-PMFbdh8(m-Aa8I^_$O zEw}@BvQ*-a%X^P%e;pl%NhK)HqSQNEl6o?P7EVCg_!Pfl7pJvJvhD8`CM*;&=f~4# zW-d*qq%52MOCgR9X+n{FnL}Z3-mb{uqU}dVDO&rzao*=z3Is^Q>3~~eXAP}ZKs|sY zI+|4`h|M)LM_^deydpo@cy_G;I;uq24T(g_cp-21$(nH@nlhQx1)Ow~>+F~%Pi8!f zh6rG#dvOuIF4aOqqz7UIYgunhtM16h$S1u52lo`29(~i5QJhPwB{p4W66kY}(wD3H zNNSmc%rmbi=l()tGDVz*u6pRo4s{xInTOhCIjq>RQjBy9G#3^z-}Nb$xvCXoX{M3*WJ(m}9@)>Y zmPD=81ag6R!RJq1GokRGaBKpM_p8MD;s=i$)+qijET$~0=@xn2;RIEfi~XLA6Ss+{ zYvx1w17G6WPEj!nS&JPMzwFkgrocn*TmqJQcC_s_Gd8QPl$s~chTOCw~}r zZxR9(vTO?+6us23HLyL(_{gpt^{t$`lbL%zH*kTRFfr`D0^Vk!ynL{oW(!UyUam!U z_twqaW}VW|EIBf`J;$0IFs|SrPS0!}WW7jw?AAieB6d1I&WhXZcTp?t@ z`QohtTu#>@yMK8eQ{*5r(fg0dZj!NiEu6GVu4RsnMa^*+W_!PApz3Y?(Mm)DTM`cU zX_KWSy(Nc_=Yu^K(K) z@`&TNCF)lz~7O z9`I)R%I;xk-1%2K7s038!OD`#owU^9^FAkAcvj{;i!|{)a5jVe+O4w0UFT4uwhBe) z=~uh5+WH6I4CdA;>F)}_$)g!(%xVKb7=}$;qu6m{BQCfwc53P^1een2oWtifk!DfQ z+47~Z^v(LAgi?5oRvdl34zdn`b0SCTf?)j?uY^DZ zA>YHyTSJ z=9aAkSHVN`90|C+QgUYYH0eZ0KFvA}xC<7=mtu@@Z=X0(2W&0t>0?Qor)vB&V7bGO zG~Y?QU@eY{cODS}o0sr4J+PAyigpzV!8Pv#?LounXbu7#5~v!Io1$rFAQNEs>X_Ke zk6kbN;tciUy!9)THYAnoT$)}k=1t?KN&XPjqd}g9^B6EBe;PwItw5lWpY|}jQ6bR@ zu)$8pN^p&G4^{l>6$FGEqBy&8&?t`Sbb-rb_zn%nk@3lCJ3GAl>E2jw7TIp7)%^+( zS1bFja695kfAlS-(0RUAz}fP5K|+G#z3_mF=H}hz!gO{V^$EOmQo^tN3X0ZRxgNKas-#((-hc9D(Vu$y5aT9 zNn_|C6#|W3sBj% z-a@!g*)V0dR;Kc7FBcW105xhr1rADW77yFe`vbSA?4TA_u9S;Q0t_ix5s@$vJXBe6 zam!(gqqP&5&{Z+0t)G@r3kU6z9PW|6EzDOgYgalo|CA z59oo(*Bmv3uJ|Cocgmd{gCaa!`FrEd^llk_D=DOT6Ev5RN3g%`vPGjo?3VZHrRljN zZn_<#K-+cs&|;S5nB(ML{39|Q8Ydp0;$U1%P}F7ndAsUz)U6^MRJVo-d*ki!eJ<1E z(~U|VB3*_Qb%@gKo_Z!R0f=t$5cfW{#rW6fDA)dOIpw4+Byk>zG2O>bqsUtXAx%tg z^f|w5)BmzMI#0OiBv3?~B%v-l6)eTQOU-XYp8_#uer;@T#-R}1D3LIoPgy-X)%;D| zkE`7>xPrA4*}u4-&2j3a-e!>;0TZG+IWCo9GTCH4xO2N@v$3{~J6=YFBGHDO#e`E? zcY9*aQ{dDjTx1=0R|^s;X|invPf8N9X7xK9&X>6X^a3M2aGLOYW^%^In(|wia&HNK zLeBbw8gmZmujie5-8#Bp_5+!_2?b|U_<3rMP7cOmO<7j(JGx|ykKn63Tcfovr{U+E z6+YydX2}XLeln)@QK79d!*{m~T{e+-*2rrDjH%x$_7l^{U0~Nm{Yf(-#3J6A@!ZJx zHfbg(PKFsc2zkn!cA}a>dh?+Nda;LIOGbDK0}SbU0GMn7-=`!P$!^br$yX6KBKVK) ztxT_7s9A)*v2WfEoe<;!h92VzUid^K5SYeE_@aY?-_ew5B0!zsYst{Mw9n*Jyx9En zQ4Wd6)pMbRHa%=WF^<1EHXIt9I)G^nfy}X#v!1=zww*F1B-03k8bEJgsmqcLTG+Xu z;1^#6nLvqPzrL;)gqlpGY_GKKm`kITvTf#Txpvl|jevQx9?R&OjYV^I!n08SkEyo~ zXgciP|0xLp8K5+bP*G`+?pClcLAsHY9x*zGj1nZI1VmAglu=`JmnbsEkP#9Rj*u}n zV86GY=kfXe{^PIluKV2Qocp?7M=5Y3jn60MN=+h8Xj5`Gn8_5b^?@CX)n_5vl;aP%`R3&K1m(qs)y!*WO!{Kk2MB3C352efluZZ}1r=Du zB&Qlq$>mqJ?>qTho+CD#fH47Hg&F1QFi#`|SLbNltZkO|@{NyJxS2t>;ZKu3=k3CF z!;4W>^s-B0lIIhv9cDVy41Q*IevG{AU{Gs!&&1EtQXH2RlAy;r4OZcbr)Afx;($D_ zd%G$--V;kDQZkyJTAR3Y59a3yXEt!>Ih7-bZG8(`eG|oKKNVUu#mG*d`u$~#zGohx zZgzJ;*FEXQo~IR7>sx}$x{=Xs4nj}lm(dJ=tRTZExrh0p)ig7|(xRrnPP$|F^Yi+4tluZCjgB6v zl$<8pJoVtC*Ab1Iv42n zFoCFUu|)6Kx0LSij*#Nsy@*<)^@C@18+Y-f6$qkjBcTe+=2Rcb-+_e#guB9jnVYet zzScR5qHz%25Pw|5V ziv`t*knt;|Ge9}sYjBR)b!EGTembPB>hSz7%}po%fr!!5{E*n(6o}hI+Le`Vc?EyA z^z}Hh%s2U<2(HbsnnU|q6B?#47?GqJIVc}n02;*Ka|8`gom;e<&nyu`_ocVo8rM9W zn^&$WaqP~C%X}*5$T&$WI(&xP>dPO)#TuXuL9b`~1AvHrGG>Ht?9Awl;(T>;D}heS zbEoyhUCN+XnrCK!{-2rluwZ|nzu7dhOLlrpGpI5JV_^jMFE&2M_0}yBL9d5XzYm`i ziF&S;p#>MC0V=Brl%H2IRsF68Q|w6wc1G?}nqvvr*zziPwB2whrn%>Q(<12)%wK)$#@3 zXlun`Qu~M}1jZqxc5_78w2OzT@lMQ+d>p8oJ?=TnYP0v9Qnu3>N|h#w zqTLC(TBU|@2cNz_+Dz&qOEJlU8r-Aar%ftzl}{K0#r+7K2Fup>M3J7WzJ9-hJIFr_ zcOA3s3z`K1xTWiNC2JZ+obkfVZncQ`^E4jKd{osdl|cMQtay>R^6OWC?llB^;IKO zUV_fj-SwasvXk7}!%Pm&$A(V$s&k}dw+nQaVO*E3I%U)DnE`(F94y*Zn~eDrfAALt z@s4h$A~9uSgl>(o1wg5OG+^$HndoKYfv`+Hd62{Oknz_enuND}>_7h+*4O=Q)406# zKkdZl61M_@2ef}ygI|(87@TofX?wD1>o%oA^<*xJw-rNuM7d)GE}HFGSGvN$vy zTgtVWDDAtv8TkX>5;12bGy&b6t+>6OdB5%XDA(65nB&hA;Hlm*?_J1Yx{yuo!RAT@ zWEJ-c8E)0>HI~xk2;Qfvt9=?lb8_8l1pBPX=C{gCx=2;2A$Sr~!+E3d?!7^=IP8eC zX<%JzbJb#v-96=HMGX#NHyx@EtgdvljC=Oa&oRbLKJAa2UC+$CqXrBYSl*N;mHA9^ z?^OM5{@0h^y~oXb?UFrJpmoI2N@?U-vd(IuV8}|01yiQ#0&&`GyaqTye zCIiuA{U?+<^QlYTR$<$XW9bVTm=-Qz8^#tibprbA^H@1wB{j%)>^}TZg9=tnok#KRFI#6TCGui3-}D{hrX?2^L^JS7H8@Ksm_$D~BFm1s;WWKL1-UJAvOa;~;7d0;n#W-BWe>>WTKly>k zuU4vEU|*r%O$sCm)_xrv^2laV`lwIjQBGt)QUg|Xw$H`(0eJZYnQI^+$$(e9f5aAP zVmg1lFV-SafaARHTxLT^FDepCsm_$oS_Mk;l9C?L6|jQ@!_fof(%?OS$ngN;dXnS!GRxI~n9qw_^n1LE?6b8kO$S@28svoD+r!;~0h~ zl8My9&vmk>clKaNo%tP^A|*AW{h;U^1}#e8cYaYeo6AKy4?{wOuf1a*Xt$3nesgEa z8Ja>8xxA>L;d*Yff_t9-F?|fHK}BWc+R(LKrw92FXHM#Ok50n~n#?D6j&f}&MG*s% zapnScY0ZYgL+@cT`uhGKfGfi8E)EnDeRf`CCA)7Wj|f-0b$%4d~u= z$WIIZDOT3Hz~m@0R8{p|`+P+v8FUzQvBa4F3vLdrB4duI%G8Vl^>8MEm6pLY-A#Z+ z`1JSmJJu7rSXGs+4?x0G7A?PjFKgtr3JKyHHi=J|LJH8 z-1k>R=oZ_NwK|uVlur+y`v1V=?@Cj)eLSoAmj?1rzkho@aoi@Zz8U(hW7d|N?!^E; zdd$APDY2h_J~nQPf35w%vn6m-PXCX}X;aa=Ik2AORbo2@IL!6>qpj6(@X5#PamtnV ziA_CEZ%E1nLF%H~HJSy`7Z%0)EJgQ9+GR_X{P-c5^pd91iH6)x?Lca$`J}m=go?Bz zIyfV$*8Eq!j8GfxqFw_u0YffE+-~w+wU&CExt{FoO2*g3l&~+PURFgv(N&nKvjul}*cWKHm@Q%S><_z>rSN z*FIg=p3f3cH;rO7`x(c1=gJE()nUeiyPAy$sdl?RvA9!0c0JDkrbn!`Lr*1YV5sU0 z2*wFgYKE@!{|5gVN)j(JUy+OU>)eYcwniNYYB(hH|4y7vQ&C2B)J1-7ka!Om;CU|X z_7L;9YqrA{zY&c2bq23_;JyV1H!;u*>~=INad-_@Z-q4Ns^D1=`M0UviXb`B>%7m2{cPHK5)xq8~XlTh}QYJ z)ed}j03PIvN{6kXntux{csLGRzRMx9N;_j@eoRGdhdTq3f9Cv0qNbLh6MV|i);4<* zL!N75jfCSB^%^$Cm2cN(>Yp(R?+^#+a@;!f>kX-RLya5zDHX>TM<2{o-jITGEEqVz zpD?t8UVd=ZZ!_{z){ww;tKBa9z1@xE+}cln(~-_7ln?=F>(p^5c_%5!*!$)+5#Nav zP0tcID4_sJO`tC-1?3ed!qD)r<<36w7srDtO6#!wbk$fvpPZfT9JrATGEysYL3(xMtTDq+w%m?x6T^+vzAJ2kjt@pz1n`W142rMQ>jU&^iE#Iz#=WE5WVuY-0Lw-ro8Bg2V(EuTyq|JAa8G1kvSWPoR1%F)APL_ z#HlVX(#I@9FznL5zVuGex0k&g{BG?+xJ*U?zwn>0Ap4~BKUkMLr(?L|+hQ&ZB*7E5 z1hwM-s52zRv}du`agoDAEJho&Y+mnZklG8cqIgO2_md5sCfM>=uf<)iLGx;hquPqp>LUsnJ8i-$=yN#2sR2Ovlu0RSuyhP5OH~o9$ z_*X|$nr*m40{)bfgbhaDdm=#3T+;L8=JC$+2xq%_o^qI0MB(8(y9o{(RN-Wpyrtso zhGDS?;kz+E&n!YSkoscsGo{dH@*V z-?Orv+jU(3vY#9mVrc$Qh>Hf<$sXUgml5Ha$M)<(($$7{68FEQi`2UJ6+dIrQwY3Z z$1Rdv>GE+ly>OWPnj5({fH$*9ZCs@sF4lXtSl@yubH8(@KH~ADsvdhZ*_UjKWPcm* ziXrGfH`lwAZV<|)2RYB953}i1N+_tP^b}LDln9G5Cs8B1W+_JJTi&M$Lb7Xb3zdA@ z(W_=f&KPN5ho(W-l}07$rZtuxwcfmXNu)+~GVjnhXmTNWh+9-P@au*JmvEF-;P*#f zewQmI^`i`C08V7b7lF_Un%MsewpKY)X`;gctzT|?7$Nep({qttmE3{E#df9ew`G!7 z)iN*f7BdiYM~ggJo++%+?Pud#rx-YN=v|(QMpN#)`YsV;>YP`Hx&W2cK#O*G`{M}S z{U{x}E{_`t91s5c<{bE{w!=PS>pXgz$vugOn%si(j3P8e#KqHzwsZfddMl_AtN-Mu z1)A@l$4oPqP9)3QL;1EP~1jRYd7lDVHCE^(7&C;}6cSF#CG)?bM zzwwVGzc8WzSaue@dbopFaQjNWmM++ESj+qJ)ehCwJ{kU}A;}J17{40EY`-W7wHSvP z4_@!{kJ2>ICD4QWEl>XQZz`4--YbtevU&fc3RypWr+RF`UnHUjV+BGx#nnpYZ;|Vh zb}$({quw=ban1$IH^MA>toqR(W1n{Jry#ZG2>rLMmxF+aZk=GOJ8$^==SJY z*Ck(AqnIn6G5fECESnuB$e`&w)pzRiD>XuX>_vAbu*x~1tF5;^Uf-Nibam<{at?7D|J1yHws56g4|$lVq4Vz@ zsjB=Gf95Mf7TXkWl8+BhBa1( z4g`s^TP2H8YBTn!lD@{9pV>JXNX{(MKPCwYyHzUPJ z<_t>eX(zD;c;s@NI>4s1!`4=~$nYFvrZKU_INXWrzc7)^s%I}kVK87rQpJIOGO#;5 z(w(X7Irqdy0FZvvN^xa=0g4LQyoO-oA##srQ}*j9v};C0?^ZgMyqHPMjkhG{7xn=q z!~-sc+uZ+T?~-7~ecCb^15g}w==~#|-WSw$wCGN1fbanzbO2-ai_s|5af+7jbg)M)N?08flUd?hh zR(_Ut_jrbB_Ntar-aZ}9c3lhp3Uwyu{v?{LsYs{?@Vjq-W7f$kpGXZ*qm}G!QgN_3 zd|?jIxnNzqpj^|}_ULvwf8GYMe=`;mRuJV-2gvpEHWzo90-NC-#9RMdlE8Hzr(@1Q z+S86f?fZnH!D-NTrALd8{s+yx==8K9aDGkOXANd$&c^ns0Snw8%zN?5%JVeh*kE)E z>cU`e)$8gSd47d>K%S`zugS;2zlCoU)P92SQrSB z!8XFv-kjG=9Q9q651^gJs;;nHAr2iEgX^_&<PiBZdICAg_mMG8xdVxZFq3Gstpuxz`Okcu^))N-GAhVwW3SXNo> zn|jr9I&kzG2^C#}novaZ;C*2JA2&O!&{bZqXTYKxJ4Y+WV3ejy@e09(>5C>JO}q%= z@G$!f*SWe&*x#~)6D~$X>dp?bGvYR4F556xtP=L$HzpF7TkvvGgFH%K?+XuYH0qgU z%F*Y4)0Vq(+Uz67Z^850byhn}-bFe=HWaORK^6<2T-+1-{bjb9YM_%3ws?y9Xz#{P~Yv!dNAJfHf>YJDT z=Y6?6pq;$G=VtBF`5N)bsmM#tx__(6N=lzMRD8SVwZ(DftVb&Xyb&gQN4;!+wyEgW z0*qyCe_XP!#<2O63_*>O!t)s&ipLNenI*>NEz*`U8v_#gpQSB-2jqTafL(n;cU%)lL;_LoxDboc6VvI>ySI{ay@4!Q-S%b!8?w6Wie`l1!rX{UlQTK^VIous+dQG@fZsYJ@AME{9R`IeZtp3uMmGut z5U&Ncf;~_AF0hI==bGy*`*n-L|_WLPNgd6NAylL8t7m9#p`qH7z(x(WKLtQJr=h+0dZdN-HNv`?F~8`&h)+ zh*B+y+whcZV_b5@@2|d9fpNc<>MgKk+rW<*N&WIaEhUu&W^7AX_HXZGJPOB=4=ngi z);?BlUjoLv$p|_cpo3qg;Wj?7H^T1*hfZ9odz8n{8N;+ zFb(gaA`DD6s~In$H965;nQvtLT~m@NdiyzAd{$n0uXK-9{k!(Kn_kJC`6_Pw*Wvqr z`-_2KMjhh%a?8Yi@R0f1HnmyHAcPBw2rX@GLrC!|mO;^3hXdJCGQ8Kz_Penz1N{kD zxBKonatM!(axY*FsbRFT8at-4*XLZJ7WKMEtx()|7;S{L6W#diyz}UI>QMInK?W3k zOu;C=;>CE7M9AZYYnRA(jJC&8McfC1Y$)Zs^#%bE9$NbdeFvt==ph@se|YnY2kIVHH$VaZn%bV59fm5H)H44N=O$kR^Z@@G zB1f4U`%$mew)|7rJ1UFdd}0<(3)}LgsUABoTx5-_xO>w)vC{go#ce2OQ>E;$Kfiin zE2PTthGW5Rr>lF&BQEQ%Sm*xzs_jc{4+G$CX@{R-8^6?^M1=g}ao=*AUfs$q+b%;G zaK1WGz0&vtFY{DrJB>1dz_*@;kln0y5&fR((%ekEjemZ;o9eJ$L%p-{u^k&P(PoIq zTl}U^9NPQV{r;U@_U-jSo;ljL+3R|Or6@OH`PG%T^=j*yz$pOj=He0it2M7EXvTK; zsI=1m?ktNn!+J*n$qO;1_fO@=qkW;M(<)T8yj7al@`z>r7EgHImj6_dn|7Y;gV&(p zl~SeWZP1o=O4Z%cAOnKfCVvO&GxQ06ss94&Y+lK1q;WWOQVU50eJ|!kE4ZV8qW02V zW*puOD{tl^wHsi*xl>=ecYKnTD(0@RgC4(!j{H@K-NN!6#2?U7z=HY#;TGi5K(om2 zz>BOCEpzeQBAsS$C{5Dh=ZwwxPY&hPClnn6AIgL|-O|hQ?_F3SSpW9dGBH5^2$FjR zGRNKyqBf@8tb%!q+9a(^*!-#0{hlnE@Cw@&jJM;4{oCX7LG;}9>|TlxWMQ?wD-D;FvAJ z$?t&Wzrp`J@2fUa-RHE?E8xaFpnWP{8M|%AK3V6Aw*D-wHa_ajBgn8o@I5N2rfg9v z*ht7iY*RDHMe* zEAoS(g4X2ZI69?>Pcb1=u z%Xa9)`Pq@AiCtAb5M5#)ZgZ49tNN+Q znu_=11M<1+4ewT0*JbGJ=7l0;lf8diYwP`6s<1~r{E_`o8)@DQ5|5CAqkT4uy1ctF z7MTnw`&xii(18rAVPPhv%I0$}dT#UE- z;OPa;yM4{w*2Nf@x_Qu!a^DUt$9qg?yOG!V4uTN(HH)@p22^c5mnC=y6i6^`O!HDZ z&oSZj!mBmXap0!5@j!NpxY?aoeD#h}uNqIBam<|Z<`)-t)zzwjPeEfNp5d&GetO7* zz(&UksPS6Lmu0T}?Vyf(Xgb%Q<;DwFbn`$^~ z``4vjGmKkJzrIDz*UmKFo@O&^*=jb0=3zdYU|kMsyYfF=;A-&b*UEuo5n3L$h^l}S zS14zrA|Izq;EAiKzLL;%Xg3l6Fz3b=S-y2zynM>|^7C9OcBW4S>qR;H>iEPojE2TN z?XaBD7hfR*-Q%D)X|i=-8H!-u!I9u~h8w@S3zXmOp4s$&K+sE&NuJo!a&FPCmq~o3 zoR;BxUhCh->%e=3SFmlTh#n~^k8qth!1#48-jn=kl2dZsLkzug2cBb^bIqfrH~CP-MH%tHNB zt9mcz&68cj1LKpz!iJaDW7ytO57m$FS98lEw*61SWN669v*^f&)A)u>@_gVA7px1K z58XpUHGL#UOToVN2XiHFE`gp}L_XC-X<~Bat|GJ}Z$)(I-xqVB;k;4n4OC=fpj*~d zADsCF)hDu04<~OX(PKS@5y>Ms;d*APf6LVT@nz^af)VPa?j-+l{TjqJ@|XYTj;~sn zc@Rcmx z7gBE$0L^>fj`y_NoR#LcOL@&aGEg*<{m+#K8X0XyQ2Q_*(9169pK~_jMnXIJr`!>X zD;P?K$n|w9v325}L4|EUri!GBy`K1&Ld#t=TbTvW_gkDpx-5{`IY zu&OIXGug>h%5VLybZKPm0(L9Gait+Y=ily8=LvTVt6kgq+R&i<)nx*YkPNM!V5u>) zEQRjXdjLDy^iq0UC&Lu;~*`l+`aQ1M(qseZ=*^1-Ir2SdN*gCR+#ZZKkPjBzj(k z{vu6~AbB;B(hvMkjG@b$$s~z3l*i8Y_+BsZo-?9IQ}Vd+KF2K+^pAVDzRG0Y(&yG2D=+(Hj zG}$S>#gSsmocuKqUSMjp(@yfN*@J#Oj$&IMOmsH8$b|E*ZgNULARmrw|3JUuwJd{9 z30O{}=NAOVo=>opTV;D)El1Tt4T1!5GRR0=A_DB8pH+NOoHiRU5YgdR)z5fM4*C2t@Fj>~-ySJRogO{7QpCv?X z{#pLylTXoL!nDj}3kYNTuA}aqCU4xW0FQ=;9dpBdkdst4t-CvCMra%Uy>*cd7nvOR z^LfZ?-i6X_(*!-A<1I_$58*DiQsATIP{U26?x(42*l0yz;}BY~QBGmjCFs>xUl+2J z*97^+1{|f3Q6h^?RJNJ^+!18)4EjrhXm!ynq;0;`aWD?lfv>pJp`re`$gLnr4?~%L z=cZn^*;ZhkGl!`1{G;ml6s;|j)<1k>P$Ego%+}fQ`A`v`7uYMai|nK>iFOPOkvU_t z=GB8aoC!IsMeWPe1+Cyq zpZ^JC6Lu}_*U zkl6Ooc4$1!{?2{^ZWMFZ4x4{|a!P{1iRFQpur^cPw$rm&2OscQ3tLL~Evp)z;DD`i zXX`9f%^dw@^hKz3+-ypo zMLSE5!Ecs3j@b1CFyU5bQ9oBE*Qx_ECNlT7)7c^d3Y~BR9FlyyhnMPCLMPsD@rd<5!-{4=CmQO% zx%>ib!O>7IvP9v%$Zr<-W>x?EGIJ;bc|Gb1b?d)xwXWDRyZW~LpG~3#$|-6&)EypX zHNNI+M;n^;T=^rG;Ddd2*?Mmm00MRM?ACuB-K_w7*;*Stu}S6ao`la25_*C_;QLo* z6R<+OYM)S4s5iyPcJP&kt#{pRY|n;ik;;XfYNG)8ivBcDmavkl3W zEvHaaVZ|*(np?=!X@#{_04oPN@~AQ3sr?t3ANj*jXqhjLi=<}|40X@P-go{!H|&D`B%41R=})~xycdRyl~ zX#V*~O0%?$3;mtnWfjFC;PC1)#9r_v`7g$}N4O?LVMhcpoH~3$vimH*N6Qbw34FYU zTL_|^z^#q!Don#xGn|g^p)?y%rzgRpoT=e$&Cv4T-)Pvn23AY#SfzkH2^;~hTRDBY zHEVpiRkDo8Zm;BHWjn|klT+@?bM5#7X?}xH^^oIFNR$j+4a=S(*9QcGb%DB|3E!Ig zul)xze24e)Dte`CIHGaXPhF5EOq{-7yRlH(i6X$JxKDR5|xfm(g z*4U0GnA`UAtGBarKsg$}^FIo)^jX`1p65*|TP6&wdtJL+C40&f&WlT&Y}xd%8yoMy z83!PzJ5WM|+@$g3nl<21^~#;n6w+K6<+*L$z4Stv$UEli8y=ukRN|?5Ll80axGrEj zad9)Bb*YiOb|SfS;B&G%pdNOps$dScu(f6Dc#jDz5{%XUy`^%3DqTh>9Tk8z5XR^f zut&3ZhqOl`j}VhE=a;}mXXlf??WVQlA+*OxSv1$qLIv}`&R(y)>~96{95XbfSn9BQ zphz=JX^ao(WSI5Gr5CCPr@H)djj07^iuqO=3GX^BHx_55DjCr{UM+DhJKqXdh>)}89k!!k8k2n*|2sY>e|^k2IuFen{t{`kWY?XPoC*oN=)-wld<_i9KNNn|hHzOa1e*ME~>^<&?V{^A|3U zfbTNhnMoy>x3$0V)`R01n6H~<34_m?BCr@yYN!0&B?g$DqoMY+tgu~FZScH}@Bg~j zlFSx7Srt}XMQ*I_>xGngg802vDq5X8=z%J^Bo#U_N zH0^l}!i=NXE_Ep^B-V+kzuooBvUs*@>5cR55+9580l9v6s{kn50cQZ*D0gODEjtF};xr&ngSg&vU9j({IZya2Hl% zzGc*X(P9?K&IBS~Kl9rlWYhqI4Ua$2!#zCXnZHxN@92#_H6g=)3!2?9@SL!(QaO~* zNh&4OenOanCe76>v)6uW4rHBg-x}bz^$cP^0$+--t3Nah?z!+U;%NW^grW>ntl?7P ziO&Sa=D1UG<*yW`q%UnS*Ft{W!giYHLOf_hcl!Vw-*?Th=>zrhRvHBunOGmM2Z{!D zmwc!{$xcnAq%FuZw#DbfYkm&I5b<91Hdo}S`)pK%@|(w(l5(|xPPvYfrKn#QO$N=7 z!u?}UE?cmz+rO*mmA~(3x12Y8S|}z-#e=$a42YAVc3kx}j(Iya;Bw4JqmYUotgq~% z-;BI=svm%#@D}Jgzbp$Jw{+A)pBI6|l5;be=H^bhBw@@*N_{2v|4{JOh_I((4G#ruA%&~>Ss=Zs_i zC-tq`9-{;mYy@vn9hAsN(S~iYBy0g>O=X}|!1=zJu1yPF^c@goG@wBQ&-%%@xGqO* zpU|40aK$I~JoP;(fESh#oPumQRq9V({8E5Xb-U+lusO&dOf4{HTUUyT^c?!X`@Es? zzjE#&33hIB%ZaeJu!8btZgS|{r!6Umo+O)`SEJ9mY>^FANRMN`9u$WdJ01L?7G?C4 zp=M;b9OFbjw68~kG7P`(+7){ir);d8G~DQ2xdnZa`w#PXY(qfaGMwqEy_ zLnGxAUS-YrkC>NK68h@DP#{S=4|}D_U`&5a>CSGDC#-(W2NE$ufEjiG3RxG-dcBAf zA&IZ71mvK4)tX|XA;=QB=i??$I%+*mP z{T4nsYgX4PhkI#mq%5J0FIc&h=AFl=aizA>zg+KLO@92p+YcyRTmA~{DR1ioJ73Pz zjGh{fr&SLnC*OF2b1t#0Z$8q4t@L5V+NvqHbjF6!b|JYe@NZVGpIB$ZkcOq9Kf4x3 z@+v^_EZ6y~Yh*m0e8xWufdMoh(u7~yf^&@N2br8CU46Txf*YedCoaS9LL#Hw(ia1* za=avV{~ZwYmOk)sTb|g|Js<8zWaQ(p1?FrK4XVkWX^bXwW(_gpu)|VBXa_2@M^&D|8HT4ep&g!9s)6NCPqe# zuQu=9Xl;{BIFY`4F6^*hUuoVDYf1z{)KGs~_3q3thJqM-yG)PVYqn_!t7nM)RLS0{ za2JG>Jj@J$4Ch|E>Diemy8+XIMfXo|uBTG~f804zphYOds zmWJnwOTp3vtrTW}<@ulQBbPy*EnS+QYT`a3uSFxD#|YsGESBRGsgaWE55meBlJxOK;!T)_ z#<4u-jRcl<=e2~1Nu;a-Te`&qlDs!Vc=WFP!Wm}mF9xw}KAVnTehmP6ssFnenBn{W z%&y@h*QG&~ftz+xa+2%ICw1$btYYeMc!}Q=ZivsoC;Fk~RAKkJDCb?00}W$mv!LPN z;-MSPv!Lk!pbs4CI=w$|6!#gRVWwk^+tIrr#f-in_h;tm>sw$$(WTRZ^S>=e)M@UT zj%da>Pils8japIh?hWWYNgTtnapG;If55;xPXl_Dh=f#6 zYONymMEYo|?gPozL3Z{rZvv;HsS;O`uwE7YBynxPykqpVW|xkaVPuS28ao-8A$G&lqkHKFNvNBE$ucNi6zus~Y>D>caqbC)?Dct39 z&K!^`CG`(U^ezeqL0>&PPI>BAB1&7DX!kYyvn|55BDqvN!w~p$w_S?UF3ZW1Dv&ASS zi%b$OYh|Sl3_FWb{}ybv-BGexAH0l2LxNcpBm4}6?-1vA?w1d+)2 zw`BT3MGiSmYNtH!nA13dD#DFwNDEt)RdMPmysJ&~ft zf%@efBH)^9$c9V@z8cCt%tQVjnA?g>P3aX2Strs?Tp=?Ct7b^?49}{)a%|l-ZbyK~Vf4&#E?=a+Fu7Z)c$z>$*eQKHd*< zdCT_|_F0hVn7k!8B22|3(#pF;!q=x5b(>t&*bj|p@)fKV*Hy~KtW_&v!#+r%PRy`v z-5Q2Qb}{AJ&MD)L(6jRk<tM|a3+0=&;m$4um7r!0dq}B)cWpPgKize8Ms8o%=bTzo1sdTNa!XN=v(P7G|&23G^p||A<+tlV` zL&CmZy7)YAlsPu11RmeBhb589pgVqXSb04BYx_kt>5;qLWH_n!ZV>ov(e;U^S;#)CW-5ZhdX*bw8YR5x;`~e%0cYX$~-YCHRn2s>YCnL&S!XQW|8#(rMWynC* z?A{N2M3XAzcpp3A6Z$RxA^`X6Ric#>Sk{c&<&cRy8ex#TAtgp+4Fq_uh+<#1-uCAi zE!zm}ES}DsUe}mWPCNXUsjd3}w@f$>$QT8H-4QVwMHg%iThSLbli`kp4rTW@^9(`| zVZ|UwPflde>969`U#q|{NZm)4qRW{2NoRq5B{rYVt=A$_fNC8uIo}IA31%A10DZlr zBnwivTd-wDY8^+^E4cu%lw1oXda1r=WR~{K+4hhS;!v-y*e<7tNB3n9(z-l7jGz6( zrf@q(%k*8zwIk9=+BM7H+WUrr)`J-CbVIhbbmXS@+th0J-)aAWQ|ZukO3==qT`LOn z<|m!)rq=j>K%BjB^D_$=UjVldOehCnhDTHh6@MK7mf8A0fqAz46?Q5yH~avfm6EYg zh|^Q?jfU+zng>&V5wujf=FUskqMFajC@_beVKbQX*hwYBeiXMFfbKcI(FO1>(BNGQ zwb}7(`=!S>sghXyk>R{ap8WH&&jQA%{)Uky4(pC(D@tRj@6fW?wVsigFXw1Aj7N75 zp0?a@S|g1HZKieQ>?eJPN~hhJ*&UGItdr*~N%*K<@4xTs4`#g(I)ayR6giVFeZlML zRP%n8w0DrtULZ*(&ib>}xWqFd8?B$*&&+fH4vdB};3d6xZV8}uLu}7DMh-R5(#vsW z3WIdd1F)`4J|HvMAKGrhp>7`6ri+1;C4aKJEIGgvC(jn|l86J^^Wi|%curGyC!hA9 zR3IYr#$UWR^(Yp!AmrcA>*^VT=%j$ug&*eTrUo-!Tn;VW^}qhxGAMG7larnPs}}Zz zbyI5V!gOFf?I_&*+v~1Y>nu+R&q^4nWr{nanJ&=i<@41o;Y*+c;Rq+BXgUkd*H91>YWToV~18qj}fj{DIB#>BF6kAeg(Mj zaC37hWRI8iyd0psE3PF{FVZ?97>tDDP-;Mtn*Z07cwK_K?ypq6Ng2qU3|I*QXW6Ma zD@}^xn(+&#v|WM=As%yIVm!muSF#=`jh!mio|Yy{ySMAt3N3~nVP=am54SMiwtloV zg?2=MlRazqjBfSttF$4~T;z;{GMwdhnCi|t+1MHtZ))$=E}R&U#|asW0}3M;GqJY@ z1Sikp6;RzuL^~6I_}v#sZIkYi(zJ}cbj4&w!%O0{F3;xZ%n$Z!o^6TEx?Xf6dX=d` zEjm);L8rT1A!$^RUCHuWKcWh_AW5wDj7Ha~d|}peK=WyoEjKCIqLzv#_+o^tta)MJ zv_%=FMj03G4}?{{shF^_zoz=tztd=wml$%IzC776*cyKDYB9yYB6YM%<1)Jg@7>E) zKYXs2g_wy8ka!0%tzScZ2H_;FYZ7s}J|>QOxJ~T_)4f*D`ytoIUC4{bK@HuxCMhxw z8#>n0)0ENUXh??9z2S>?wCKN~9#oJBbbSytwC7abU>X5*9)>hEd@h>1-Q;QK*HtRa zx#`f*C5R=9B`4XKOceVOffdY~p< zWxE)y=-%@}2N=BzV-nw?TfAq%2&PF_r&~~_kK%aILzNo_+|^RCPA{OMPHyx&XxScoF#2`@}Ucbp#l z@+CnXJ0>Cs4X+k#808+3Qsru(+a6e}M+*q7H`cFXBh)6<<(tuFyT}W1Hlvbv;`Y4o z$BidNyjtz7PHxNDAcwFa79zBUa)SldYi?V8Jv*!W>XBUK#lbyj4^CaB;8h2MAthfE zEq*f%Y45((JEB9-k0bm_-Nwx-y*M5{;}_G0Bm|MDYBSgYQlQW|S*v zRO6Z^@l()lA9vGI{K2y8kO4O@Nw_#$k9&I`Sgv^}!Bc{D_+c62YO z_Boh$dRnbi0+J#2ab&*iZL_S=_k@n&+0QTNPpfL$T$F=9aqEqOCn0>FD%(%XgVXkO6m$+5XBH ziim(d9A_57P}y@ASi>A>xwLgI2WTAc^Z-g_#yVK7y?_u0_Sv5VIk49i>Sgp_AWmqG z`Hd_Nkdui$Pn|ZzOgJy>>IW&fUq)@uwjP}Hm-_diq|*Aa`0#?cJ&R;CE>tm)MnJ}( z^p+D%#e0dN8jv1Kd=h#!g?^&ZlVz!{aucIsSu`f<;v1)_s!{XQs8VaPK!e8$fuc#AP<)|}&cy_%OLb4~BaR-xFA zfmhRn){$zC2VcnO?HFz4a#R+TJhctzgVd&L6~wGpI&0KAXBlhJe(adK{PmN(&2g0O z71QQ{c~&!6)uZ_RlK(rk7!?N{dOeovR@05EIDo-A5zVek!F2o$AbdL=lFR&9M=<-C z>x~d2i0dgkJ*oOHu3{LV#w`}w-P;dbjD*~AT4D=pv z6Icg~6I_^d;FP+zCKx<7Ih{1&#-G~w)Awu!-N92b5$Okq^6>hmjzz)zRJ=F&1(?TU zL)r#M9x=*!0SuyD*yD1nQkvU4Ik%w2o#W*YxoIABN#F!8tSv=PT*yr15vN`7}_s7%w0rdm||1C$Kfq z^-ID7eIm)&WXC5LBZ$6C&rxDBsR2wJc@>L>>}+=>e`1i?KK@qq(C?m2>qgQ(0`SZ6 zE<&>Mzz)O%v5(Gi%T&-81ap2oxuvmqaB3c&TREDL zpR|g+!@`^_0;fyoUF_Jg$=KtTA4ng0I5g@Q_oFkLTE=Ce{f`*3h8XRq6#M6rOh}T3 zU=a;H*CzLKAmRGEkFIjgaf_&RE>js@*-w|nGgS>R-$cC65a1sgmT6rto!+FTmzIf; zEnwuHKWnWsH{`;s?-Uh%PLGL@+`Na9Og;i#E43Kv$IcTFk7cjKXVZYps;sg{=yc+A z!bV5lGIIvX+qqr8%ax_R7{~dw9)$XWRupNB1H~*p55KgFcnqKcKd}B(lsBROByIn8 zM0TyXWBW`Gj7da4ok?!qtqGPOt-UC(5JB>49R{v8=VtZxt@FECNVOR*zLXCUk;i%= z@a+N~Y*Trq%?M{B(A~RD9_-)qRP|ZI9TBhJ8K-9w{{NUd3x}rqH|$fwkQyNkqXZPB zONr5-pooDW4I>3fam4795>Yw?41DO2937)4qSTNYrPN?BYQTGVey`8_{sm_{=bQI^ zU7rgR+ICno#VGt{(#eEfc0$Y=B{SdiZ~CmuRO=!Ns1eKUij#iM^?O=#8Akn(^q8JO zrGCbH(0S^%NbZMkHo%EwRoypqlq*_{S%4&-pCnqGW=c+IW&hhHuEXX?N+HVaUG;8h z3}Q1caBE7)b6%10m`we{?}3})GG7ZdZZAm>`B0)bfXbsZv6$>J$$-z-n0COb_#u9$}qveKWjiJ9oiqcX0|>+=(Hi~vT4@dFM) zjYvrr>*#emei+ANZFVmJ;lZdjxIo&wLsUB1s8RgM!0`HUd*_EA_Xl!;nPt~nX~7`{ z*J24xC!3u*Ogi5Qx8=4H9K(UGb?6c$=mGA_hzyA9T?hY@B(>wUPn7U}+GTk!fY@a83JG#+GT|TLr-3Z>00lQ&&E-185_DpOVyX4&+CTr-W5%? zXu(5ZH7V)C#qWln64t9ZMu2+&D%m{c2~Qh-cY3`|i2kI1J{VAeE}!4f^OiF?n&CEX znNmW<{cLHs#rT}6Wf^^$tHv^oX#nk^FGmY2PEWL>g}0Wk6FQj!j7KfSV@{Pdd$C~z5@1ypu2LZqIt@m^l}7>YBH%Ig9

RKp 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

{O-Ta*1ik5l+{@H^(K?y|B2@~HQ_ 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 literal 152797 zcmX6@cRZWl|9uj%M`PEH(HgDQqP7?GB6TC?^h z_Kq1N`Q`Kd{gu}%ubbySx%a%!Iq!4t8$$zadKyj|008K9b+n8CfC3Hx;BhJn(l)^ynev>_BQymty(n}OVWPFCb%6&W=d4!Rn~$lb!oy%3~k>nRxW z_ZRk>KP$H9*R-c=9LwOz<-h7}y)j=s?70-3=Yq;c{EyqDX9K`qMUQ^tpA|v1-@Hdg zPfrpN>u2X45g;BPm@Ub#1Y{l56$eaJUvxjKwKb$8d-#Hw zvB^*uak|2XQI4>C{uMDt$IGsr-zDRVcv`$Uc@n&vGGy&`DehwsJw|Y#)7j-|h%XAd z*SB?{c1gU!pTxg8Kvt}}z?lwU<{Q*&qRksE-Jso{RD+iFPcE3c179I>4~9f>2h*l* zcb(&(AL$+sUFwPYRrMcp37qY(|FQPD{socrB(_hhyzW>SsoAaY^<>c|8u26bXg%0Q z=ur3ZZ&m7ds(DJ~8sVs+4+g;+1Hw2(n=auDw{DvR1Y$gE!8dgL5w3NXBckKOlSktL zGFLy{>5K5wdC=WV%fEl(Q9&BQ_7JP>NmyA~={-N$ZL+emLg5!)^WD2b zOyEvLIEZ1fkOY2IAtbFS;NU6h`I4qdA{i>E;+l37u-NqUWA$g?A>BCn1Uz*lPL`8A zflB@fIXJqo3G2HBj*dV~1YK40-=l`1h5qVcfNZMWFBi7xMoRTZWWa#!N2xo=oO|yE zWQv)sUlmZnnveeEhE^MAQMIqZq?A#R6LB_L)()#e<&);3S%TYx^NjE&BBE&z}HRT%Dcm=P9 zXJZgC`?K5)2^J3Xdktb&lLgGp%>|+ksre;-73}gh5^xt*#n%mRAcEe<{7mmO0pZ>dnHW~T*afqf$f30Q`lG`C}9HE<` zA4Cov!|G}kZaa^Q<F{##`SEC~jk((%-F; z6+$Bh0}FZ*HSj{R$G@+Ma2D1yM^{~yW)FImKzttgEv;#uC@M$%^D5rXtG!Y?bR}93 zcw?`X3uHex$QrN>w>cZZC=E%X+v=Vzuss9$Giblke5ngb_-g4X8oIz%ihbTyw*!T< zP=K^Dth6g;!H(C~4s2tOQb|j~qzXF4_Af-EEZO07qY1x-Nvpn`TRv!gJ*)}|(f`_tzb zU|0xI;&9;2$r}n#TWjvC-g~Mb2$T|I_OVhd!GeK8>%0iGbq{UFsp0iPwYDfcMTrEo z!#`<-(swZ4pq%c&f)s@QwqTT&(vSowCl+zQYwAwV5eCH(Pd5iRd8Z&<{vVGRZ>yHp zd53K!{`6X7fwPdFa1%X#niD|IQ8*zORmci#sbh5?u&P~vb!JO5MXJlmEXKAim#UxY z&6ax9%;rPk&Qf8{RemPw(sJ(wKJkw%1XaCe;T^CAM{RLv%8lM{H5NTPw^~vmF32>&lX{8+uPe|<|WqOhGDL6M#Rw2L@~GaHHkc2NQnaJh3f6k^tMTQnkkv#_G0Kmi-||V zf}l}kpyB60oTDk=wI>?=BO~LjvYHy=ZUVcc^#vZ(PoN?Ugeoi7`Zd&knST3_jZ>cn zl9tTl>bgE`?H^axl;B-#a+4kHe6rddc)KPMtJ@*m^qvQe z@Or?7PZ97g8VGdTc~1xK(tQwdAtw`^N|&(Ok0EZpyCZY)OK4M2X7kVA=jeeXghM42 ztS`!=uxN~`2`%_qaMGq0d_gJ1S5$CQ)t z6(^KU2<~!kOs4`7VBVCN?D2)w5C3vf!QP{d%|Jqo{AQ8y8U>%b zzfhmQv4;5NJ4JYe3r>`ge~1}deXq>@t@sCFqp2ZVuuOVNK~J7@ z#FP2qmPgbSs*iSG(=-dE85{mPH@<^eOo>~;H{UR{YhcCay#6I7j9_4dbEA?b;0?;Pz(GqX0x_*=Leao z>w%*~ac#4uBb#3XXk#L}9N3~m_&BQx-N}2rHz_@mKKqxKqs8yQb18Yk7t0Vm!YHGc z!nJ^zpTN^!coq;QOMX7N*eUIO=D+b+BlU;p+(t_eEj6tlKi+0hzb92E2nmknn^TE~ zh1#&IrIJGcw~Q2&FsT!yD`O~?k?N=FF>2dPY9aV#_F&C8uuhXK zlkKDs74wgQ0F*r+P`xOY(aNL&D zX8Uidg<$vn=lWTWE!FR~7~!ScaI0QF)oXFQHSZsDx^Mn`n#I?BI9RpJ$l@ch9G)GD z(`wC*ZJ!#So1lWf`2B+oe%&VMG{xuse07x7RKYcYt_ZVz7iYF7;I7tKLOt~5I{*w- zgFGHZf;0GJz*Kv*un^T{d+mZFHWc_-kODi#%)R6~9S6OFKuKvN3spLp;*{=8dVKD?gRU9{ok z*6f&5yq@kgY}>HBIJ}T-6(DtHqo*;z_b;WXja^Mi3E6~~qlRJMq1lvfMqGvY)uPI2V zv16*nlU;LgOmo10C8R#^XruS?@=})yM#HK989Hfui%Q&00hT$6)K15SBb)6vM}c&!?6; zX-F-Wp`1}V3zl(THIF0|lWNK{POFveDmnButM-pFb~)AUd~yuD-6ySBwC1XmO(;ni zs6QBy{bC$|YV9zz9U`)}CQp^fq40?HSNKZF!-oG?+_ehBrqAOJPlSz|O;L-6vi;$G z?sm5^7s*yNH8nQYjVO-02}G-!=ANPwnUk+pK(}rj0EXK@1Db&B`nxB%^4AfKff^VJ<{#CT$u8gDNEoeR7( z_Urk8#j9_{_Sh`>ihQZPT?!nDbC@=9f3Qu-gdv&wuC z$XD@)NOf0zZK))`p|t5J)EuaXp)M#2XCo&$o9xGlZnv14bAP5%-alt7>rljaXVnKB ztoV~kEOmc@ao5CzOIuQLasLbZvfdlZm_@zbXpknvMT zCV`7&;V8E#<481Of+flyC-nM8uW$h+27Nnv`gd-_@7JG6glLU$&tbI`1f8Z#@TVNO z)TfRr<{zbwySng@huedkrLG;nwN{mVH1RFfhAQSR+FaVl@wXj4$7v;pTUXpZbDQWq z=+|cp*g*eDh@W5e4d^A}Tw}mvm@kA>FzuXXpf*eu7_Rvrgamkx9OKapptcU-UqF&o ziT6JtG;oTg73e3sIL>y!K|ncI-NV0qSZ9Uf{yr}_NY1#(9=SftN)5eg(tKXzem&e?CfAVAgkcXkZGg9oC}gF{L%)r88o5Fmmb&g{N+nn7rCYWSzcZ5AOKZ0%?Nm*iQYywT2j} zx=bsc%GhL(u(JA`Dn1(+k_lL>DUS_MWwQnq@>7n*V16+%e0#pHTRdz_Pd#sJ-*6=U z=*Q~nsxF&O76>OvSdR~pcKiyaqQB1Wd`pD}gk{l~W4)J1Udlfkdtbe5D$uR*^-!KH z{Q2iS(JMA3tnlo(o*3xj%RYSw`%CitjI_a(uSp1F6tt2Wc3@d#CINtiRwzvPU`p_d z=lk7RBv)Wuuf6=cib!BV^q9j>^o@F-{P!kSPHrem3^*Y30h$hk9dkS*yIQVoFcjDe zy9GL}lm=01uPOUL^n2%2tCDKTO{Uy(YAdmt{G{=eNz5m@VOlpM&$rG3>W{09Y6g|Kg zG^tmVLFRODlDtS|OHPI@Ng6NfbLp=;R9q`uW}(Jx2`{@yeSm+DSL520#<^JeALV!r z%}r3iU%3CkCdY^)E2G-jm{14A-ObHS5%k4(yET_n{K;HsKjoYxg*>V7sF_=j!17OM z1nyA59OF+xH{GVi(cA(d+yS^YIaBgGF0%|*vwkrtC39O&O^pvxB&&Djvh2|TN zSN>+m&^;C}Ej9%LNY3sK8+m7CWQ=cJVNIL%KThTQ5xVHEQxQnQySjFbr)_e0@*3`3 z&1BKH+z*n4t92#X^yU|nZ2;phgP%A&F_5A!hTPqU)K3%ry!CgGr>AT-1q22 z$?1`imQ54a5lqiM6!F)jtAIwA=DU%pqn;2ziLA_>D$ok7Sb zpZgVf7`Q&)9nXcUg~;37z9BRU^s~|>)aoQ1T8tXAG2!hs0`zpDE*&wm}YgmwGZ^89a|+- z*8T=rZ5=M|pU+A-q#>u|3C`_Qo7^hr$78YJvXt*W5eG(fOoKQUEhO z4CP;IXbsfks$mQy+6SkEQzS3EnEv5g3V3gIr1~Vq2Jz8<--#+JRx^JbDOYV3S|Z=B zgx+@DcQmf6M$B*;VWbs)Qv69ytUI16IbJMqG&pnY7P%GFx=>BF?NiIEK7;%B>DS1SU5^18gr(|&J zs_i@c3{OjN!6whYOil#cy6g)^U1T0{FuwaF^8Y7(Cy}$qC9CGL;%t z!UahP<{xB6NW9{L+16${qDG7%)!hL-;@D2aA{9NNmJ4teP#55^c610?_U0+N_EVmfHY zmtRzq4KRfPVEx<&zQLw)53ab5vLQYHHZd!0vP8y%IrS$jpDiU1_egk3jp(C+m#pIa z57e<=Q}>qlA8BsP7EN+8h1l0_^xy_X6GGg&rfGTu(z!!Mif6`3Y={N`$7E;4e{E|H zxGP?b&_zjc7SWYKo{&@g%n}N3PQD^=rIt=qKUsLvL=ymw{(b&xVb>SR=S@}86Uk1` zz<$KY$o!z;h zG+8VpcPT71srR}_l%>jO!oDY!UxDxD#`aVVX^UJO(H9vsFm`tK*X+RfvCx(DcTpas zY{++JVH_P-illR9fgg|hBD`B3Y6VeZ+GfQfW292MleK_{&rGdv(_f#jS9?+`h*1mW zwHd*EE!;spE^@#qGpeo!4Y;uUB##lUU9^<&9Df&BK#vs09Hw|Cts0xL+tTNS{)!b2 znIiFtDvx+CrR|g4;8^DJs83@qrBRTyv@~f->?%L{B3}(fB&g6|H)M95f}vj^Jry|H zX|&kpdEMfo1^$#prr}2hA!C~n$maJdOzl@xq@6Iz)b?G4+cbP};d448tozVfniw8Zk@3A9%LnUl zU;vb&uUi*&?Wnyvqt)Zb?c51A+7w+?guRuO4wpEs2!*dE)oc||ScVvQLN)o5n^%d6Y|4q`baiEb92hr-W_YGev0RrbLc__F3N zgTSBdKvCiZlRPBB7GG6ieb+)@o{&TTeZ15c;&pF9ld(O)byGZ#ga3gnr+(GEHS1U^ z((vs7bBVS)OWG{^x8v`e`Y;bEh7_Erx7>1av=oJE)dO#ZjD`92z220j_eHyMZaR@Z zw{FFV=l-LtZD@#Nv%o}=kE$KLCb0l3t&7hhB^>ZF$a3b1AbJ0~zG;*ZWA zeSLuRu|4=vgEF$_sy2`eT4p(!U8KRDhyY4w{t+{;cRqn(7xBpUEBzYlFJ(ZWdv(lBYGKuS#i96D@Jy>t9f# z{}t9iGyExG5w7@3G;gGam*=U7hGMz|po223y!gBd@ek z5pW@@N3ZY3%kr&EBsvs5`ayU$*Dq||&pG6M{Do*i2|}-(n*vlCxu9tKSul)XwY)GM z-CAlw28*d7Q?bMg{apmZhZdpA^)^N~M*(@W*0H5bVTb9K{+Xgu5vea4VR@7+cYx@I z(BQqrGGwNeBE;C1CKfzw&?3hgE+`7V#M$dtSwJ$I3@J4thHnKu7vX&7=jp(_%YLp8{J)U<}r(h z9v)G*NL>Go^iv&W`cr;Fb@x~TiJ^N`$hJO241hng+rCL-}<9?~=%6e!w znm`3Cw(Dg&7=WO`MIR6t01h2Zh$$=je3YtW^JnD~0H2)*j3txG_si5zu{tDvJYw_F zHXIDp%U@0oCAN+tnKFg7UmcCUlt27*-!CgYmHhiqoOpX+00|$H2XEU`8EMAP-^bi2 zEh`ugQkgY7F<>Tb7M;L}e*vjQ%!I&Z@5adrZTu6YiMYIhH(8V6wQu}{po*(d@ATi+ zE99@*J?OiX7j!0ruCoE6ollOtf*+R3u3rvy#*@RoyQ=a7T>+a#)|AmjYQrzF%rp~Y z$|mB~Yng;N9*wi7q!w){U4YzGE3A9&2^pC#yaZ(ly3(F%8Cm2c{oa!$y*#_w1R!mw zl8B{ZfU!0HUul$(8VBdhN7>bYpqZX$AwCTchaE3tY3|V3(C)4pHyvnghVr2g?ci6? zELrS8_!*G1nsI|?OZnk!4v0$Q1~Alrp2W=`1E1s!F2{uPV_XH6=hg=g$caaFi3dOVs>87u{Jn%bWZlgoFXyatySCi-ej%* zToVl(igy%SN%mf^f1f!KBJEauUBVs38Lm8;`eB#98_`ZTG zsC##YR_-Zn#$DVWih}ouIePg0OyNJgcwP{kkbacfDdAtAfG`EYKSuN!kU^IR^QVML zTQsoAawFSQ-^J{UuxgrO7(aU>+n5+|@~WxBada!CZ}52ML$O1xgZ0-h*TKp5#r zfD(+oK(HV5*IdbwW5Jt6gysP61O65K1vy}}p}haMBGj7f155h2Bl2DQfs3ra7L6tO zdJx~Pav51~`Y)DrYbNsVWj`yg{^li%*--WZ>;q{u!ZWP`SEMP(zvr*LP2pzwBsTtT zpR3=UN7zEsEb=Hd0#tAX3#gbCi1HWm&#|CcC`v;(fieM06^Yy036~k>2QFkfD6Q2u zkb14ZzI)uH6IOwF>BPoj*?f~y)0>L5hUMe8W}5W^OSm$H#pX8-RDnm9o{5OHZ?zx> z$aG+@5(_d@xL8Ll4HPXC2|H2pfcE@Z*ejXYRnAkptuVp@I1Y(Eq=Yf=8Ii-r z1^>W}w(7f9f5{^><|tuW@pL^?tPht5f&yLa zqzo25pbp@iifTCh#670O+g3DONyii?s&sG^v+SEpN?0`5I0#zXS!$n0QXp#+T>5t^ zpoJ}|{+4smNijM6u)!SA3YB<|7(J4XFUt1#dOPU@a=b`xRCw8=m-E&@Kz4(T4CYVY zvK~LJYrn=wP_QCqV-y){;83ygl>rx%(1g?l!Wqb*?e!y|Td^EL)~^`+G(~2`0dLd} zm3^id*=(?4K?Dkdb3khMJvyBp80t92HvPueekr%^EXQKa7ajWk8X5MJhwG6?FX1gBxa(dDFmYHiwHZO$!dR_&U=8=wbc^YDbFjAEPu}gWGIO z6SFRaask*MUQr++wn7^`suPVmyS^!|as_~lTxkRIJ-iA9VBLMpl!}U1e`&C(Mx*kt z2-L{hQ>##j42rlvum{5pua|Tz8d0KOs&11d1g^emmr=S&qc5T=Q|Clqdj)>T%lj7j zVOg+@un?8_N4P@w!Ur$p;_=Ma+l5}J27vu2Aq68t544C@V*Xho*0>LhlOWiLy3@hC zlYlf(YA_Bo`uy9 zc7L;4hF(;y791*c*!9w&*BU}r`_(DCDMG~puN7|`;{v9zMm$G-muiK#dt{gLl`nlYUoga&~XJl*aQ z6I!OQ=HA-E&=|QjjdjbohpvdVyBBO>Pmm7o7<7%NL3DR>JK2e~OQ^)q5n9{ZqD{3W z8czv$t6@6AExj>sM8@lscZUGSF|i+Z^e&IxMkWNKQHm~Aipj*Ax|`y_4D-Q>ISd&YK5#HjBa(P zr6G*+k_+~KZ8QR~=n279kWStKmIff1cmvfUkj}3It+I7MeR(JQ4CZ~{OMFOKSkuv} zvHU?)%4^DO*NP0?#p^6vIq~`nW=nZrfnq^Lg8Vv8?>uMpCgvJIjhuL}#846JT7fF$ z0?rjbNez+BzDIrw_xN%kWZUpfe)iGdTKa3GZpeSK&nxfe86l>|b`pG>u0MgJt zop=tk5&uN~Tz7iP+%mAHMg}+V%aSSD5|Ug0!$V!dtVgw&af1D89jkEETLm^;ZvH*Z z_|F0($Qg`Pq=SEdz3a8K!?p1{P+18@rfKM5_WM*xc`Bfs0(Qp13A8O) zEU;~gv+!;0KIU7$%xbNd4!!UZ4X7|b@9N%4{P*0w&Asq=i?M%c3DD}_JUCz>1H!`< ze7Vu56U#~OXa3=0QGv$5Q1v~H>1iHQFpO;erxGfdMImx>6q$))y09onMBE{@dq5lE zPZ=oW>|+Y)Of;8}dpCq3oXuXa&3-@DvZKG&=-E<6J^hNH4_>>`?ba{g7Z_VDB^D}fvcPgi0R zwWa`c+~&t+*zSxzEGKg`k;RO%S%6{t;YFPkBH8GUoooldvF2QpW;O-Wk-`K(kUF>? zkI}>8Dj=FwuLkJK>tk-OVkqyiMdCJtVrwE%-tvv)@TAPdtlZn8&jvYhdLH_QQ*{<@ zcA-uFH3w}6x^u{EhHwojTf1v0UXi-{K%0I2KNm7!zsUrk5?hnE9k4yLEkByi4Im#H%)m*o zx*MPCv$`FjTH~xoC0H_B7k2ALX+Z6^s=9ilLO13VqyPNP$X0{J{jp`!VHQc^RSHHX z3g4%iLc!=Y0rPQAZ(39(sG)Q1@hBNuhb7%`6Ka*A^!VkV!b7~HS5n0a)al3ihwol3J+sSPW_~@Z?OXSNE`r_* zJ~a0_4cx->!F=aLU$QEoFcc8JCKoUi$$yv9o}f{M3S^_D3ZLEf`&6U9E8_A*IJ10~ zG#{&hUPMQXC-S_v#~}0`y3t4^i!6cY_x0+ReP!uJA16>3 z$)*0@5^&`%d^E`}OY*jRm#B~EgnPncQq=&-f7VP0QUTd&2aG@)h7uTJ1GG5p(1$xf z8@dll1|%`!WyoQX>R3y`V^7HuMMQ@^CmxtD9%Q=fXnin5?yvJ`!(@wlN=+}(5 zI6F;XXdUd+IZj|nKeV2qgekyxBfqszGv06?q1Cq$nU+fOm3u877`lrr;;kg52wk%{ zBr9gwVK?=Kx8G9mrZ`!8byJEeI~sClu+u3X2GjY^sf}l<4^c`23E}coC!pwgP1|D~ z@_HFbiiEFp)gD{FDic)|pvI9!reS%E{x>Ba+S*H6^yZ2JWnkBh56Yf&AwNm>EUSht z?%uM2#PSeCUqy!OO;j97Q*Svi!7ID2a-!r+D+qR4-XK7yVR^ zK+z#<=cLXo4LmHu&|)NYj}d*i#73}g(#EE$mUzsY1K8ohnnU+LJnE6H3ya4|aINYC zN3T{hSF8JbJIs<&(lvww3pfx@oIP{aBaqE<=g|7<&GQ)2!fZmX8cxKaSfc zY53z8pDH1a6Wd)s{{|xu->p%3Il7*0cTlqBMM6Ya_Ki#g>4m+R2F{<5 zA^AWskzmymjqe3^RcCI1(T=jqD)VZYWJ)VEboYJ**Ecn%C&E-r)t06q_x*wBQ1R16 z5-(eL&X5Sud*eFbf@K~>=8^+0k0u_y{bm_5pjZmP7s2S$j_P1}6smuiM1ou7*GZJo z#}nWhX?j&l;$D_j0Xo7MOF#&k zhSHeuFS-I(?tpnbLjr9M%BBk>In`xJe?|sXPyd=Jyi>(HyJTc5(3H&+V~OFeF5D_f zfLm_&e#G5kDEpuTTA{%YxM0kcd#EOULbDorZB5%T0moQ)X0ib}xM%o|r`o!oe|-AT7SC+~CI9XvIPzc5|4_8Rfj zs_ZM}{%aOJqiJ&q3RsL@V1LI+oy>pQ%Z_eSLZoQ(cHSg;bm>HMYpWsdcO)uyr&kbl zmQ}PCk_h&W4X!V|S{*e_0qaK9LCwpq^*R5$nKRp7rD|xRs%x31dIilL0V1(dmgr?Y z6%Vgg2p@V);fRq$r8VLVKmyOHG=XmW=U*;lG&osqRF*hN4dhvR<{fD5KfN>B3QKOO zW~w#q7UsKGi{>lOQJf4g+Q1IY6^yEXUS`kt4H+UB1^AA04lTXI1g+|h^v-S@tW9f& zoz0dueL@=XRL<7fJz?LZBPoeWQ0L#WY&&|q7Y}S`e__+1a4J*SpjmV@+ulj*1}20a z&Jf1V>h?{}g{YB;{L7Hg4t){aKw*tK*up5i6y=T%yE#|DX_)d9o-N(Hnpw|qE>ZT(0>YR91q$*9wmv46J&zgX!Y|@-ctpPFJ+Vv z9hb8f38RW5iof`QXtM3fqfyIC6zxap4Zcpqi$c4{wYIFR^OrGj#44c>ayqn zKJ=%mS<>YWV<44-YCrp#$T5}L;h<^REay}Wrp*DW6!T}{>Ybsafb|X~1WBj(-XmBg zgWC7(8ZA6Y?6&_&Zzb9OND1*BpL5Dfd*c^T4BI}wer9s@lk)G>C#$+r7|6oNgN`^~ zlf3=);EzDU>!Hj>R9@`? zs+e3B?g8z(!qIYEXFjF?ZUBNd@k|#X;SUCMy-~*we-M;74{Y!0i|ts7v!|(EtKl5` z?gZq>zFuOV;oDHoL;n%p2Vx|t@rAW^JJIu}zQAHx?`_UX)o=Z8KXqGF{G<0GN1r~* z#~_TMLqA;J;m__0)YLy4OpiRP<{`DOAT(*B*N;5Km8`pj|7`%&O*Sz~U}zo#oO|o- z{$T|G=OiVtB+mSi8@^slK1%9nm(8+oCxMx3W&L(X(2J6aa07;5bBTgd)2b+;rp9M8 z`RwV}_rBWED^xw?SoUcd!aD}J-ZXErh@1G$AjAX+B_NV;dCwZ2)V4QDT`#OT10Ym5 zcGBnk-L~qzKhYU%9zeEysLOHmWL35WvV{fpm<&CP`ZR6f<3tK(FFcL;pexhtKVYMzM>F*r{C*U zOMtr(RT8#3a2EH~Q6xd>vh>JI1*1%X|Hp(U#RmP{cnjc`DCY@nHC^0F>RmxhwYtvp zK@2>8fp}C@vo@b(xa9YVG;Q$Stsfo@%l-GgsM|>yC|m;#r|dAXiZA=p(+-51QQm4! zNd52SjK&q_@!Mu9tUH6v44@%iQfDRAh@{RzM*R5G~>QfOm=rY=Y1wj=Xvm=hHULo7ytph z^AE7&39h6Qg7qO7PC7JohVNUL1Bvj#Xc>4djinym_Sl5?ykg=z55UCkqy0kX6RTuI z4Nm#qOkgi&M7^_6ert0nR$5fbt}1_SCNRwt3(L#}jO07Zq0D!vgM}WawtBN_za2%NTs5S_Cf{(O7sXHfm6%7pTvf%B0U)%y%U9>X zx&sIx@a1~SkL6*=%e4bGU|+u9Buteh9Uc2uGed4$$*4s>r4yOq@9~564(l&zfAEOu z6xX+~MJnVyD8FGMB<3uOt2LV>&efyu0`x)}#3-g*=}inSA#gD>zgU!!K~>R~iB2o$ zEs4VLtnFVpCjTWjjU)Mb^K9c5OruCvZJJ=>1D7Ia5VUY>_7MO@|5yFQ9WrSARL!jY z3KcH&z)XAO-ibEpDu~xpS2VkMV5tg8SqG-m0t`1AviKTvVL2NOMfCMFHCVR5Cz%7k zmJKzA&adm`llZPB0~aG6S0+RXi4>wyBv%g)tvtZ)mwiMC%9yG)7#V7^xI1OS!0se_ z9j*DSI9cbX^0QUmI`(aOYVl(jaaC@UXuE4?n%*g91V{3Cg4pA_Q0fYvrR zRiSWKU*mK$tt`1z-a&vj(b+}p?o&SUmAqLHSfCj(YuoOC3aL{eMbP=|?9`f^d2W?Y zK!DM(!Wu&V?8I{2JFxmoqEaUDQFHyfVW4Mt|4f98TjrXz zIH)YsY~+KV-Hp)?6_nrSl6F?`bD_lbbH$QkqM;H;N$gB)zu=RtYR29UN^DJEc~LlEi)-Uqtod`$;Z`FTQhB#K))s1-nnY`^3d$(v88# ze_nFDAue-WX(Of)DNp&#Vhtyu#1osBgGV=??$n5nA6e|W5W~w(F-zQylE0k}Ne}cD zqBunqGi)v2Zc5?VXYP=BR8o3zDs2VAF50^a;^v(%&i^z`3%86mOB~4j1DT}QNE!Ke@6LMvFeVx_Amqp#8)h_<8@U=U+$#>{d zeP28j81pYlw&yw-%z~y3Y*tS35-Vmd3MGk%{ic@@Z-@&H7bn2SUUDzv$6rE@@%{qx z=%;!tgQ~TxQ^Oi(+g#iT=!*YA9{Yn_wk6r?rIQECR=EOOJ zteu%))0jmxS3UP`COsO{$w9Co1gSb)jKN|jYkZtD&)>eKCN^y)=8}i{S~a@Z6T{Ja_mK+!QgqSJu9T2&96X?0pSH=gni8cgJ zS_Ch#{$u194w2T|h?O*nzUoMAiJ1>p=0HHGm9!8oaJ1@ix6YEOi_&c!rTLjzN$&lg zM$i>Mf1Zg{7*;1BH}HOD%`W3$-?M?*^XWU2J$}N{f>U!mFDHql>ksKGR`;iI%0?d# z-hip%-Ivx+CWFmb;LhfsXChhTJ##vPwMV7N{eB%aU4(`bn2j%TC2c9kmD)7siPewa zC`yE^t!e0}7=EJc3pi{r8^B+G-FXq3L8K>!W|8o5sN&lB>dN@ezRHvh_rm8wT9{ws ztcE zc9_d!#;#)13UGN>#ja39MXy20(zuWHIYY3Tb99Tp^RJ@0+fAa3xPo_o-!bB)ix>BaOR#k-M9hn&L2hr#-Z9KL3^0>ftM*le_lA+uO?rpnc*p5g-Q7 z$zmcG$f}JmPJ-1$Pm+1~ktZrf!}clVI4SsM+b%97q(Ufsv-ChV>E-hma-i z#W;Fen7@7_Kl;-o*P?Rqfb_s1!`uYR@DRn?>}cKI9Y$u9ZSUrQm!%zAQKI3!$6IBL z^e=bX+}>I0-{_^esb@COG477sGP%TKZZA-dbaMh;O9@ag6@YvuJiL zi^)zul$W>u{lJ%cz1eT>`epXUxuf1Eqs$6oiN~tjfd{D?sfgWq-UmQ z2~hQx^~mqvMD;UQaF8dspP&l8@u3OC=&+xTSME~bT-IvLg5IHqf(ua0{jal?H>q@T zC^0LGL~E6^V+j(&&7E&>-emoLirBd|Dsa^&@Yl27OOrjtT1*p}(Zpa5obN>`fdsS8 zy0+Y6pyOQrtIHQAfmfpZ_HI|c*k3p2>JX0k$YQDb6h$E2L4#X4ROem4V=@^9fR%$K zCq+_uaG*(7Ja3Eq=YyY>i4kN2Pc=n;zUS#0uALbs#HlpJ1%*)~FOS)`AyfJXK~9@# zYPsirPtnny=W^aWZ`GbR2Z5tkSI1J!_OI%ND0J1P;lH^tU+m&`aYSxnxA5+d;)9!L zN3I>(;10_E57*tN7(Dz(Iz2KT;PU&L_Wo9yK36^nZ6?tNX0?e{U?at-5HnBg`N{+% z;8!u^d^$V_M3iyX@yotormnnq#1ebgv*79(YNA>@(YO8rv!vEC7ZOgiGTVG(-XR>^ z^rRPZ*ZV_td4j?`kzMHb9?^A(h}ct`XuMGCC&~al^G3kaKF^wot7)-a z1ye*~$OXG)MJwm+{1{fVp1%Ww@fE+m@U z-F^-OE#0!%OrOlm#p9FX?(fY9Jd8?jvRRc~#vD66&uI6V_FCEhux(xQf?k59+M(8g z(C+VGExHzW;+V*vdZXq+6K_Nrj>=?x`8qKqbOrHOn1ba+-7AmDPl~uin@UskbTRI2 zQ<-4DS?{(Fe@y`gVePt0+ z4Nv9Y!VITG5aIR3T>O9RrpGPy{;GOmwaPN_$?Nb=lB#d7ioG8DwN2zeNJx}rElS<} zQ7_Ds8?b&>|l*?)(k{rsXg>>6cwH~;Hm z4@&zZrwOsUP=!$IlRzPB(<&KD-&V_}=n3S#3 zB9X(`bzodwRs0t{ac-ITim28_>?-H1y(1CxIY5?f=Sl z;=^1$fMe71d?5K+_V`aR;GH)6arWZ6J5$>sXC{Le1NU)ekIXp#_55q4IJ%UQkwhM^ z$%Vn8@a-)v7v#(G-SGZr18H7_6Sa7}qTFoskds|oR*kp~MK8spSBXxVxy1W`ox;ZI zFy^7467PK5*~)xH3z4yy2TNM3mu<^(+_MVY^G$L?an0Aaj2jbC;_d8oQuN9v6vT61 zWfCGnLxaw}@CC0yQ*vFx%*wCs0~`lLY~IF3HLAJVL2@pXaMEGOD1_TF)fCXACjEK$w>1;|&usnU*2+Dc%-3GbE-UL{Oxtq|)>m=#$2S1p?SWJAI2lkW>bf4?duhPQkNE~THVKyp|&gNI#NoV+)r>!@1Y;9J>yqQTpn zG22f;JOT8eNG5H%5Ke@BQZ{ zhzqxQp)(r%36|__hTr)yEPr=aFQu2b62rZ-EFH;N=E6HZNf?}LmOyB@32hx{vZdIZzzEQCITgC4M zcZG~!#O#68L+Hu#1pOP9&d*nlf}}e3>N?c^FDUqPQS~JmMQu|*so>RpE_c620|_cN zj~o)n7ZS7?F^loLH$&MZK+~I{vDmf=o~?am44bg&?czQ0kt7AGVYBC{XM8uI{l457k@Sz!rG+${& z0H^fC35;rIgR2D?ZauEG?47`^pSQm6PD)7(kZr$fw_uqC~(MXQp4qIS;NL0_h-UPJz zNP>K;&R6Mky80a*H%FIz-Lgx>L9(x|;^t*<{@Jc&@Nl+gX=2!BH@2|I!_%jor$eDW zt3^feG~wnO)S-lBD_MD*^@`t@`J$t^431MF+}>s{_GyP<%6*GV^Pe}{Y1|G+9d&y7 zT@eX0yFbrW&a8Pq@YKnw3Bwm11>O|(pkwy?JPax*K)AP_+1mUI|4aDv%^t@ZrNz^6 zQRM;6BZj{0tulRWy$g41H_nE;9i};~-=mh?mT2Z%B~$wGDB+H<_?E% zu9;WoI}Xi~`0j`uSuXV0_;cw@UR&bV=3bA94-@zaLch}AMWQh7Nt-JT&%RD_+%!Pk ztT3+)h8VPoO`_nDhwE&O-@w&1d<}@6fN0+SRQ`$6tQmzjUqY-$f^1k56o#_AN&(X( zZC`haR`2PJQVDzD1{A&~SwSY8-W|^gpak|HFwL~ZHbds-9_T{mdXSv2y?gC1=N16> zIr$DHEBx0Wlu=c!EjD_3*M@f!RBf4J;!P>0LJVSdy>f>&gBrRD(_XX}>lhZc(q|=v z{s4nEUpz9o=aI%9wM2V=jk9pJkpQ?DprrWSS2+e;;$o``#>VG87Hlq45LX8ZHMFWb zRMq&c&yklMqKf(8? zBc_vy&Lr&_o+wF&{Ii@Uzl{^#fa9~;|CJ9UiT96zA!{Vrqmv|Gw=DG5oizJpcnnV_HE~5j1Tog*Fi{K7kuIhOA+iQ zHxiy(XlwSA?+$Wnj-$-aLuffV%8De{?`5l5@~APks~Z=JK`zHdAJeQbl^dis3i8i^ zzl^hc2_SkBk0ldY@D_pK6TOd28`qH$jIv{(P4+Q!*0*|4DZjO3z@Rr^Shxm5o&Q6Dt@QB&~eaomWA;cj~aufX9ax2?;@iErl*hWY-b5 zM3%0V0eqpJ$!7A)7qlNSYNjc3AuTqq1@dkkon9^CP#zRHYZ(}ZS{@r{Tty;%?PE^; zz66Fvg*zJsfOCL{wQd`lNLD_0?u)P{UL z&7X0ftstL+CW%j^fP0hdevg0J4r3=kIil#O2!Gwgv5EFq>-bS<%}0;n$4M0IAicdN zRIT{JRy27XS@;xYKXx&hq zOEed!xtE@kmXdtMv%}eR!+KtMJk*wORMHTP4{hvqy)_Z^+B4~fZ#A~`T-*7ljF_P6 zz#VaTaBn|Txv<~G>PvB~9EW<^`Ff-C`s(76^f`8)t5!k3q_dT^7f2;KrmjvnC(zh> zsRtY{Iq^ZV^ZeUC$wNHV%g%4M>s*7k15_-rVEOYpZ!6#Z(ss5_MFZ7536l1^OE#CF z1jng(`d%I{k#Dln@#Zb5P?($VF)xRvg~dYe^07X7my!d@>f{E91o_Uo<^)t_q)XGX zpC4Y|>)6kegjv^s-IDuxXYv|g-_VaVp>oCFvW6_hHa_|J(ih}J4)pL#!GV3K4A~n& za`O>1vYapj5-A`VAWMM`YWYv7j%`hJ<`}_T=(-Ldk4!VCv)ucW^`>&i znV+d>3DPgAv{hERwf`8l()qUGdfN7;He%hpx_c}+Yzeuc>=06MpZ#0E8RLAhm8{ur zTaU4J;?N7#&yOn0H+JxYzoT7jtt;*0Od5L$JFZG?c=sJq@6&`CAE+9MQKDNjNTJ;4 z?)5f!yOby}A+<2{Vn>5AS~9v?O2O9Sol^(OjF)dX*oS~E(JVp&7u{giQLZ(hYyCBw zZu$@ZAASiSA^PU~#`?m*;zuE1`mpZO3%Ez&UyT@2y`!1bZZ|2g{{khlBmb^aFj~I( z=ZlQq$0sWfU(@-1b9{%xj)Od!A0)>M@9w_bs~qw_%s+q#7jL!^?_{NGbbhGwd8j@E zww!lhq{X(#-~I)fENjrn4Osd~FlKad;_YGQ`<4gdnL;vh$Oyiw47mxs0&M6LEL}YAiu+qGOIR0d(u&RCh3Q#JWG{Hq9`G)5g`olnM6W+oP(!oqj&psnKPBJJxM~5nO9$3M? zJvV-(_rhWFGWhAn#^J;d`T!2Agiw%yg0G*(b~WsU7wcA>S(@(N<(eT0Epr!+Yks7m zA7|t{N;$%3}aqP-TS=%)etG1TCipwteEC7Z+*bptf|xb0o<_h8I+*r{7${ z`Hq+iNd#jo;|P*VTpK!LvJ?2@gY>?yNJ^ViF&sG7&uR%=xWK3%E|1TcvAmg{bdTS& z#D_n4b5BJsiYKftTe#y=L3$; z{s*|z;FC+7i0f)_Un_rTJHnp2Gw3LpyJBnup+bn5_`wUG6B9xq|5aNUL3c`In^M9! zxWN{s@@aG6%q#)4CF%H0Om-1H&zJfv4uX}GUDcxxz4dQohOOiK*Pc@*hV}+_!L6pF zI>xqKi@Q`jj`NLu{sNUxa*y&y<;sF|kFv1HGSkL9TcTD;89;w__$Js3C<=P>3 zY$UrJTQ4+I#ZZeX;Xm2PZf8N9P>P;@a`Mt+lS`VXsf|X>>xnA%E+MxSsWn#*B6F1H zY$(Z&ecAOR`=^dtDZL3uyB%iZEk9#b-+i&3=;pP!kKJcK8%FsS-V(gJP1%(h8;nVG z&3~NA{#fIC{SlFr4feF$S$R5&fX}KWdk*T!B!2vUSamyvMA6(8_+0#R_^H;*y)U=< zLCKgF^0p`U*Oq9JX@X0^a0I9VHfa|LYc&{BhKZozX5}eRo3>hye{cg+7*Q8X4jS0Q ztCGgUpM8C$s@3apZl9!}Jv53WvBV!rlEHlY4ZH&F@Z*&sm`S=Do1tLGFZ_)0Q4`}Rq(Zk@0rY3tf(6G@(LDc!GSaF=YnjBm%b z{BTwlIwja2B+%Wt>*~(x{h6(+@Gwr5x!-`J@-FpV_}!af6ZS_3F^5vY(!1^(cselm ziZaJw&A1av|LT(Sh$zh}W~Z{UlFRINxfjdKi5S4Q5qoXP+sEhgr0k^b4tB7OcYdPs z)BSbDfxfq3Bsf?1VPbxBa}$5MUR709t z>^z3iM!mQV@E%QJ3jDN(-4AzMd;Q{M*67Gcopj~5qBV2*$L3m}tirdmDB+G;WAaTp zQ!|14P??8<*QROHB7++5VtRE2DM6);t(sa}Sro~v7o}RgvAd52e&24OkgQ0W?c3n! zICkjTvvqWPp0D(^)*J98`)083SKuJe=^LtUt>8GvJ1;4Z+jQa1)_&xT>hH^=wWZ{#mqeMi`L#A-TAPsRa3FTaaLlzaZVGvA!Fw&j(I-bT@w|`- zT-4YkWb@xfcXuQq;g0={w7-TcMA}1U{rMF;q&)Hw9JW2NC<5|t;90Sk+1QgW$|1NA>5#zDy$4+Gero1xlAH+4v|%Ffs3PL)K-s4^VTQ`zI(>cvWDY zf+ez2=rcSv5gXBtzLbU$zDM;O{?3%o8*mT86byck_(-i-9jAVW5&7u7z$0Yx6ebgO z_w`9P9CK!x-#3hdMC#(mZ^y;bu&AbIu9t>C?SXqkk9${^mL9IG94;$ZaYUj;Ri#o` zkIQ#RIo+YFkx%Mu>VbNT{Rd_y!bFaHdeKLNWHeSvhp)2DQQFVB}zTm zdr!_~Witrtyxw+ddh1W0%1^`Mwo3}(zS&N;=!PQ`!P(~VrIhh^)fI|?DAVcLE7l=5 z-r&@U`6n7L^?Ug$JmYhDUnnK-am(eS0f#O3$*Bttw_@(dX`MQ0_o^L)_Y;X57wQ>DF=u$oLs!kZ;RMmN+sVbH#y4#@2Bkg)m>=*l?3WeGqfS;Za;P(& zfVue2pm;-(oYQ5=UoSQIQ0-0XOBIHXNlTJKGArL{L3s~TCQta=6@0iyi(A~8Cp$?* zfJ1rfahDYykKafb(t5hKCjZ(Auk^?zVM^5@6J<{DzpSO@d%1^3MDB+xdSpdn(<6{t zLe*&T>6?V-=M*C5Oz4K%_f-7X7HwkR3TFCmD}>=eG4fk#XGm^xg47L500O} zb&yb8w+*gE6o-H5jTYm}SndgW>1vHFxy#CQ0?CawYz~{Ao|XW8Y;2N`iYitcJ>@>v zcG4fkiP1*iM$)gQ(x(azmRBBPN=E5L4#ZB*_^Q!e7Av8wu!teAY*GVI9|R_!cJ5zC z*{xov_Ibp}gyIOI2#;po@-`wWH1TaDO)2k}*GeefNvCJhB35}ecW&eS6wR(kxcD!M zz`C~AS|8l>?z7ug;fO*TY^zx`$-J7+eqwk`>cwpIZ?pUN^W}?1pPS3q4OW+5IpjFf zxBHt(dWFeOFGKRNwtjTy(Q(PO&bq=Tc=}W0 zd-q(}{t0AthEB9AG2*K)sAi3Q-Ci3bg}h7Wp#Quh%;5lY@{_LU3ieZ2Qm@tCklkV? z7v@1u(>5EkJQK=tUnY+B#&AQiXnx54$yp)VLm!kch*F4UZaHbd_Jx`F+;x!?qnM?r zn>oX%k4F}5rj$>x4^J`BAC-s|HZYY^P?&u}{PW{#Mb2lxnx1YWBcnzf;m0i#!jPyx zswVPy=NZik_KfW8!JQ1Yldyktb$0ID^ZhtWb=+xB)C@b*UxO!_%Uqfg>}st6EsiA? z@jE62oO+(WesFE+VOjk817a=?oJXk+Rr7 z=SkVZ6OIoP@5{HWo@;$*V=AKajYZ3~{hb94CS&P2N9_4oNn6Ld^F0YwYOJ4ZgA+R$ zv+pK@>#uzG#u;e1vV(6c1){v__Dgg!(t!1OR?L^AKvp0&RntvuY z-2KpxdwI@BBdfVA=%<&ln8F&21A(I_gj`MH@Z8^+zE7qw>dFVlG#&>yFB}iOioiYk z78>EJq@l$2WEBcc z+9nezyGM->(OHbaYX{#u!}48y&5d(n+w<0f#0J#6sfgrzAZ~YR@1VD`eqm~Hy_LIS zSL;Ejq*+;_A@k-&UuBm0t5xn%*|2tvLvC_xFEpk^7l6t;s(&(_?dH5pn8F18_4ooc zxy=_?Hc9YuY)a5vg94BU!)O8+iGxHZ$+-lhOXdkNMohR3Zv^g0G6x>jj@Fut=sKC` z7?L21yRBka-9SJ+02(hxuIJKu&n+G!Sd49;9T$ezuVVeml#hxsUhhZ0kI+?2W#L&= zaq~U%>eu9@(0NoM{h|7|Yo*aBPluT5i5mNES6+%*@ODAyDzzlijxl0PkKk+){#^Sd z@7pYG;O@1g&PRY&G{&j@^gMqK!r<4$YqN?gs@~uUvU;-qL}6l?yQEmVFG{EVoh3id@B)n>lBAqfg4@t<-F9du)1p zQ+u%pDF%YTRfO7_*1n0h`P2Y!xm}nU|CdW5)hYT?LLmFtY&VxRq||Oq16tzB*36vr zrpB7aGcMtnJVVWhn_C^-uT&Bp>*b=J*63%i;b!Ay&5z685cOf)nOy?>3k<6wd&s#X z2pdPB#wU4FH>X1B_D@xBbNshORmk!Aj56lMPu60aWMpqYBmlf;06+`1ZCe#^7y9p_ ziLSEO&RH1Bk9yn6#XEkmfj{&rPX=^6bnRDN=F1bqVH#G?6iCtyy>HzP%H&GbW*m+N zmVa{P4=Lw9YWcNciDjAZn`@wg?@GukakFeY)771VcenKF=iLl@EBJwNGnQGVn-*l3 zow~{gc)k_E#A{`aePG9rPr2`}K`p&^o_OW&EpM^`e5NUDSLfe`jQ#>u2$%$>FU8r4 zKQ%bbT6mA(j(WBML>30jY_dL=X_LfTbzX&-iZ6wN$*0Q3_bu~qQqgww2&|#_37jAL zm4`1|o}8-?Okk=N9`X$TDdu_23mtsOx68bC7=hCkdF!%tlQuwCe3Dt5rJ+#Eui|^7 zNt)pTC-(-pppKkZK9IaZt;$0l$n-3Zxc^ym=1&PRSFhJC_a8E~w$ie(lspds*)8hq?0LKmHXFcXkt%;@8^d{5 zkXCkB#smo!T|nJBY-s)i{Ef@Lc#CSI%FSlQjpOfu;LNDr3wCUGgkLe&_p=c$QY@C^ zvBvDr&sm8wV0lD1>JUzQs(*wo95E=yUP#IFc@`e1@*rVHb;^V{eI%%0U8UMN`sJ6g z4-YGmN{TaKd2Xs3O1>F2*BySIC`*gB?i-cvPmt$xKoL%X= z4&8;0+%u>CsIWUVPX5ja9zv>w?oKsD9s*$+ME$@UvmCQWL)0JNuBf~N;T{Y_+bozo zd#8P?s;(VqsDB-M24DzMukv43!N~ygULSr~0Qo9#Voo6IQ9oFivt$41Qh+E4uFKoL zm~zd#iP_G1y~t(%eK!DyAqU)K4UJmWNW46-IE3(bQ@q@=t763lD4MxCZJ+$*_+oqE z&mcca1-Ga1O`hc|;>6{)1B25@4$Tf`0gIR;D#tASis|0~nD z#K@AWy+#t19|B6QitQ>XI7J_dX#u={l1`v8Vf+2RFU&NJ%D;tH$S zx2a=xBPP~(oQwz8P_v}Nb%ph}_kQ0?PRP0zJ)YZkhy5GYE3&R{DR##}8fZ#9f%rTO zV-&R@<#IGwnag$zWI_5!oBsL}IN9i=9olBamjQK8tK5F4Emr3V*J5G@L|~!Mvfzr= z))%Gb0mj7n1ZU0{^Sys{fxzYYd9Zw#yX6sEXLnseM=01R8pfFbuHQOOE#M_s_r1&4 z*;#_UbL(9-pU=!IK;Ccs_IOopW!5QS{38;0r^ei11Gzy+;|?+W+ga4aLsim5?8K*u z&lA1BWsGQ#U@z|UFoZkM2UnPVfa&JnVPrVbe6b{OL>PhNT{IXA(g@F7(+IzPx}^U^ z%z~rTPx!QpR&^reBL7T<3BOqmv`hm>Eni^b;bJu)V!2?gC~2@gv=rx#M40Jb!-&{MX;Z@@f{JV?X3F z5GcNY^`CF_yiUb8BcV3>H^QPS&<^yB3Mzqt3w@zkngu#V@2k|3h~jyYfKE@?^_cSA z5ihDYT>TJ%VwD*+?1?(L1MBoYqF&5X-0scG7kX9V0+{>xhu+H*-elVVMow#r`*e2e zQg~aVoFtzxFSsRc%!Vs7Rw9aCgnMDik*fO}?&Kn7;SS2k7}eCW1whr8!ho);!>>M4J7Fle%e94` zOiIlJ4@<`ey{WJk*0+0vC8hY*!(A zK}SR0RH{M;{GJ9ooXSy0c(lLXjq#Q2GuxnyL+Qa~`ru{@w^KQk&Tx*k98RO=x;xj> zY?g(1-EToaVkkhLxz<7QYJoKHSp$GG^71W*kA^OMn1j@~?iVGfn zH7Qxxpzi27i@NxILNO}lr#|4PPybf)wHaTD;$Fq69I5Jdrky^=nMul-HAps=3qC1+ zu+a}7f3tbA>ZuDyv!_##)&}pZCW`5llmI9!5V+RUQO3+7bJcXGoKH(ky|ldkEr7q- z4$ulbhxe%S-eq|BlpWFff>t{Mh}6cK94wjuNDSg^zKqccej5hhONG=utHE6x=(uFt zs0KT+p!`vftvpQmnYJDF2m|h_u(Cb{t$bJQ?GgVy*Ay8XV?8n4PH0Dix{(Q3$Hpuh zOUad9sdkO!UYi)umfDIT;l0 zTkVDy98$!B$(tzXwj%NAjDPta3{!G8ob|TsLy2Oi%|doompsmPI4ex`T~ zQfnjS4jM(tzc3^3m zsweGI(5q5C>$$TfaL-N>qves-y~;A z*AnU6d}GQqb~H~L=~XBMg~nTE%rO{IRPQ8$FDqbma0IB!x2pNT0tBPeg-*NkMPC5w zvgHy*UiU^u{4u?h`PT0De1k$rZ8>Vyu#!Fqj!EK3I8*+9U0)^t^TU^?&#;R7#J|=v z+t7domyIE@jA5qJ-LfO1doD+=j`ddWJ{Jd!0VF-azkYVO#2vW&S>fwKTjvi3u9uVH zqOw1we<&bWfj2Q9;crZOJZxMm5S+ZHshiw;)|2R0V!Mk*2%PuRDovl|Cx9;b9D+#m z*b#Z{73LM{x^7q1E3+94!x$%Zeh-4z<=c`+k{K9BZ4)g3T(-^11@?Y{_r(*=+yGOo zptpS2agPv-;N0KAg1k_f;llCZGr;RxZEWu?%6f?69~+EyXlV*r`OfTGk62d$R;lkc zISPF2A%e&KY=N$j*NW|w@gaU7ulaYyrv1k!Gpnq)>q*b6a7$cy0Aa8E6rt~BK0RTt z;7ISS^2;ZGAim61bedU9^_jR{A5uKa56CDP2|uG@;Xw8MTWcD=4t|2m=*nyYOiV_` zdpILKBv*CwtGu_^heOto#Do+f>IXK!x*>$I&BG(PsE6dZ0*-eoU}x36)aDZKw@wr^HQTz#jT0K^aPeQA~vdeC%swdCdeXcNIt;S9On2XS%*ajpazEu+2R zVen{uZ{4cxQ?sLV13*lK$OzQT!?~d`5ae~-~*|xN-PTPX z__8Xy8jgkoBK%AHL$biSbL~B@GNxWP24JGWrM&nlXK#dyErBs>8xC}>FuA5Pu$i-5 zuG?_%v-d^297)KnHVK)=oX>o{IX>W7ujR_Vx7pfe*J37kgb+ecAj14o-V}K{9%F2X zF7DN6Pmb?_5#I^sW`LUQ6r&@!-^WjG2^j;pp54Y`86eMhMEL)<}fS?x78OEbp}fYs#r;jRU1JE2nmYS zbL@b~OHmu}(J~X^t55H}*jGNME`r6`+?2hGt@pFFi@rgM@!Xhttw98>P0C)Z!^f(H zjRhzxX$>&?!iOI(#By_7UOV3NYxZc~dB#?JeU{yu4qT4kx?<6po~yFY&@op1>@zlO zWnrXUSN8uPUVzu)jp_xf$$64I@AT(79rr%H#RFsIcPN!Wy#V2Ffi4CvE%s+wgR?)b3eR|6Xr@F`tBA}>e`7^Yxg>U=)L}n zCk_{~D>{GuKDD0OF@(VVqjvRLGj=r31YcOC^hKfWXR$hA9`W_eu}4$wQTSWrzRcHc zigcEo2<2ARloaSa{9|lZ*>Fr_@6VFe0FBqfFs(oiYegyg!~ElfIT}prj_(`k7uM(C z419z=pFV_Q{SK#{Wjv5!B)j_O*hrtE023i(O=HcKfEMx&tN6uf^n*L`geM*5^5ekv zq^gE%KwhDX?#>T8$#+*KWwUk?)rseYC+#-_6T})2nBI>bHOj*t33Kb6^2*SbvH-z* z`;TFe#LIw}j#m#iTHgw`c%FOo{Zq^7$Lxx>g7;5;RO0^mJ>DkvWiR7I-)#5h zdOC5=uIyStEat*-K>aF`e(p`xR zz1osx2q|jZbXGq>=X$A>RRwq0hezZOvI1COYT-&@P-0LXj!~5~avT^BZ`x0C0kouh zSC{G3->YJF<#D}}wA`$%XfS@#AbR9U^^MmO3>ZG&B>-pe^{jZv@f~9!@70c^(($JN z!9rI6Mpznl_rH0B<~*4@pC9pSQ9o<`_^p}%yICO{<(>By-aEG8&XB=_$xIYlm9-(U zIs%4RX!F6SOYJ5B+!gW_WGT^*>1^$We0J4cNJ=)~bq$hj`h^Q+I)ZkO%6Qy^>8#9y ztA4D5dB!gshkw!&mR3U*fa8DR1udExix|)E>Al(#Ex($8MnV2hDN(rwR$K1VXbkpN(E zy>Kv-E?Ddu0E{s+p$LZT_YU`-kTN;)MQ|I!^Z{bI93rp7dO5=d;r;@|;iqEjpR@nG zV!^gBXLQ84WfyY!sp{|^F#89e>c~ZExigC}qNt@PjBLip0!8Kg=xH0kQ+ZsC5dRZ# zOCc2*{Cw{O?k4udaY*3HScC=|+dv0E@^>_4GTOBb%>}KJRQktVfS;FxzA`o(fx%gL zFbm1|2;Up--F|tQiSx2n6kS&nnCKbz(bIB{rbtyqHip2zauKrPl3QtwNmuq8@&J#+ zolHZE(D$&D)?c`Ps62jHn|Z(J%^f%BouaBDm*Nkl!7T#qd@t!HuZurFz~9krsQ>%RJMB$G@i0NrZ2c?Q`?XVX{*7Xe3P zfZ@AL#M7D+2NEnOxgANRf0j%nON(53U|Q)*6}cz?05iraUuVV!ZP_deMGNvw^wDNi zhdU>wzm^GH6TXH2zU44IK6g=ctUC^bPxXdFGg|nZ7L&$G6z~(0uqABObli<;q2UN~ zdkZG|@VW+Gn2fudC~ku}qm0&Up3V%Lps+I$Z)8^eb)t^{0yonE^MV#b;TaUaNR8q^Fv5i;@FTd33VAawIP-x*VcIDD1M|MkJ1hP?pxbN@6BhxNNRI+2PzjjdU zDgIWv|27B!jxN|!o*eTmy5Pj6=irVtG5r2kIA@`4>W|(sOe-x2^R}f!Pn{hWEKVF^ z^x+hdLqwDuS~)T_lChwPLMAX32#G*R66Dcy1HXh3b9s<^-hSaX^OI>i4MFJy;Oodu zRRpnIoapg}tW0m$lOG3g5E!usmm7;u%tRP@!5R(rbZmdyz^CYA5)sgqsM(dh&eD&C zzAda~<-ON^LIKZ4+V|c7WWuVhZwuKUU?10Z7C06sQp>>)E|@{o!Y+ zKd&u5bVK&ALBqs<0%uDvaA4DQucv;5r&>|7n4c5$B@3bxd*fPWky`5Ep7AuhWy`GQ zuC0Te_99h+J6J&xFIyqkZe334V?iZYE1< zoaFOcx`h|DMvC&)abf>? zZMd^38!k<9$X$JRvT$pG#7mgEqH+Pyp%!>PWAao zs$1IaZG%}3qiuI??#?|}?7nW;4%H-9);9EgoX z$9dsA*K$3OJ&d@8ho*7=iI#&@foYL|)CMN(Lm*F%sv{SZSUF1zZ~N3C3pDL=5==aR z4S}676D3+2)T%=$4oF>4uzIQmWBfats%|*Z18Fegl<=_|Elm0DyS!xAyIl?^?g#Ga zFlpqek9Vl ze)h}2bQPA>fxl1$STK3A<2WC+V!j3ld6=LVTbjCOsfmJ^Z8?e0nqY-365~1`vRxN~ z12)9J-PT1*+=+#?Cj-_taO)ND15E4ON^15$s2E!p&N=g2Yfq>5Sm5sl&r`rPKsx$e z%E;T1f~@hbluUtw6{#iU&Pyp8OK>B@F&Hw`udq{ zwKG182gcfqBzz4pwMRww9wWqa2QD#S25)p2@+6Xlb9@ix#bAvm|B8+SbXEQ^;|_jn zVgphbjxY&6Ol~;*%!Mg8H1Qe#v?lCkgwi3))`pj(L?Xp(t&uAF*K>ZGx9A~=-jVki zp$%8`2_Tm2Doy#&jduGq-Y^7vcSU)1q&y!ucFZ%vgRaZJ}^*N)~_sZ)n}{61<)-((|Zp9QF<>$~;RjMh?yx3RkDh)*#b7bGDUwp= z!RG!v{I?wxp?RLq^i-eM!WuI)qBFCR=+aBLfm`zAPw5L>7`JX_-1&bhM`GMQ-rm+v zFM{q885Sq@6G?iQLs;VhvT>=Y*L6o|UGoTTBY*XlwSdQ#!JlLwF^|yA13?ra-c;D6 zWCED#5X7kL%{3W}ZbvjwSD{Tnkrt0L$*o8&pJCPiRHC)5d&s%vkGbDq(Z)nnrREkR zsf{Y#LG+k%Z52eYEP^-!CRDf3rka+Km?9aEynWa9YvIcn>rEaDSNPYbUB`Q6U>nc= z4n{aN$As&8^-0qr+4hnK@sA*;*J$u*K_lQ zPtlGWJ;qB@*Wv6*?AM;%FcT}lrHYrFiG(5x!eotb6Fn81n;Re2gnNHpvol$2k*qZN z@E>fT2)|R6wr4h&aV`_LYr<1jfTry-$h>L+6mKzl%zi?t9(vPFd)f{=2uv}%hYNiC z;()~PxcjyO)-=vm;hZJF7$QOd&$MpTWNf7k-ZNE_@A9o446fqWo6Z8hPyrQ zc7;^i#;yS_ze+V{)Z}hR>J0_c76Xx>MzYdjw{!PTl&n#u(H-{0m zZRV~k^NFa0Wdoo~>{L&96(`}hU0-duetG+H!BK($NAT~0KM`b=6x{hh%qH1~^J@Uw zEpu~zK{V4j^ZGeD49j1+0GL*JsxnIlm+y~j#No&O(0f+^4)2Tr3==L5i6K4Sc20oO z5GaT*;aoPS12fWquU*YQANRuliw8}Ma-YLOI8om-2U^tz{0dIZB{^fW7B*yd%Cbm? zzy#+Kmu)6n8G=88NDZv-# z)-+7ZlfNR;%`sSG<43rcj%Na2ImW>WE zz~wz@4Pv=fE+meL9uqDPS>B$WE}R4HdiPCyC z=S&ed;rmxF+5H=P>wPX;B~;aM&EyCs+{)_eIko@H#tI40Gdyg%ZJgflG3|~>wbt#a z{sEY7Z&|000>I}pF?b#pye51XzXH>$e4KW`7F8#$a6bU;z@R0HTl(Mn4tZh9yuNmU zXF9j%6mJF+!yO`mYG!*>*cW;1uK)xl zqS9S4OHDtbr^(%LJ!4{muLB7_|Hre+m2-+K5CbQ=M(2JX4h3C7O?I5F3Nm#8rln4- zKzx1LBUwptIq}~lq+oxM`_dDR1Bha}WG+OWxN97o0DRT<%~%5Zm(hz&Bs8J*wLcev zL#+{l<$*YO)2*nWz+nUeN<5 zo>kKZ-Z2r=kZ2|~-B|i-dl7a|=rKHpi^9M)^u;J_(d-}BN~m4xRs$nWzTxZ4x?#x< z6On`P`wD z91@cn=|>oZK3&|Oj>#msyKV><6oA5!=n{iAL5!T=b}c(rADH+b9|{n}K*O!AFZ@YY zrIQiErh!TbqL80GJI`5Y(v6*lCt5MqI}6#BNQ}pdt+bmAzS?$A8bLHU+}O-KHCNLA z&;PwQ+Z4zaf3s48Io{*N-Y%A;DZbrOi3V;D!n$HeDG&%09As}_r1mXz?yOmzL-r4W zo#8(RGKJm={K-!!)f|9BjkIw54dxEo_z+-f=O4pnRH3`~{uoB!^TkG{=b4u3b_Sc6tNb5MaKJICC z=tK$UcuMK|^e>QSek5$U&ic-7;SG22zk7RKvkZJ_YCa3T>YXbq5tFiTSYyM0iVHVP z3o@-M^H;;L$|q`C5QA^?eD%*0{L#CTw4(jPAVYR`{NW_1;7B`AzMfhMmiVrMyQ(jC zyMux-Pzthh#?Y|D?+h$I4dwzCaqkJQG7FtJm z&@pFB)quQj#J7e1woYV><|9xFAIJ30r{mQ|PmoUEv&;S_n*)idIBLaZp%)7Z1PSDZ!Zf7=_ur z8W#+IK>|cHE$%wXS!&)Mo`2cEiag-&o1M~3Z-7!_4`Jd(ERc%#N;o_oHgf!P*W4d8 z6s?XuFz(ItOXcA%f zA4G-~e}rk>9* zp|iS+j2T<^W{+w`C)hrDaGQ|fk4|m)c4Fpes-Hxxc#fS9wdc#w~`N%vFT+DLM+;%dyv0)8pYj z{&WR^22=q}Q0p2FRD~<*z;)Rfk6gWeu?hBF=SHSY0&ib-P7}vG)rL zoGt4VxKU@C&XM#-#z^B-jxuun8UtOR)cG=Lz|YFr811imVP>dw>)5W|t_0hR0y}QZ zYNfWiA-_p^T$le-`mO(C>Z-$oH|r);Po3eqhxz(5fdgAxQCq0*w#V>Bw| ztI`63`HF-zA}vE{1V*RQDb0X=H}Cg*<6wWl4vyowpF6HNuk*ZaY>W|9&HBfw8WD?p z10+FJ29O@7rZb|o)Gg*er%OEg{||r1PD5&4S9tp55Myhu;P2U83~CTyOe^_k_^zoTl~A4Q44j$}L_DsX!@q#+%ZL_>vAvg11om z-|kJlkfr2?T8AkV_8CCw%D0I^LC3Da2-_F0KIM*5(xG|Z%2Cz{(>cOS%xUUhZ8wm) zTJILm^t<`^g78+y`^%nMkj~$a|Leifp-1To_RYd|4U<3KUO4!mL?3j1KMG--Tx62aQTh9w2%d6q5?w9z#4=b-b>GC>6mJ&y z)8DdT;ap1^Bf=+*xR05|$yiS7C6jQpAAN!fM_db;^D-dq18d3 zg(c5@N$RJJxS>x+HkKN=uqG87jPj*UZ7uVYeYDgH^N+imczo7wU$)4o8>G*DGH6L& zH+p%ZC3|Bd2&-i(1r{~4_W=~`z;zEbe%r~*`eyU-PJ~U|S(hqv?+=x)p%`Pl$MSur zLp8tnp#UZ_+ZxoyhFfF2(?d;C^4|mqACS63=zMre$X6VY&@v_|2bR zcVep<&)sTT;>S9 zYf>54Wjz^P*IYyq!?KttN0jBnT+xt7bdrX5?W#$O#&TmdOn>j6VFU<6VTOd)T{Nb# z+FJ-*qB{bUzyy`}lU7%Ag#~}ror2Y8vp`it0COQ2arPmqbB8Kbmc_|(W5y)!}huh>!8STx$NeO?m5p+sX|F2&`+c3i3S4{l{Z{B^w&e}TT*N(K4*W-_a6GPohk|)+A}^7ZfFQ$ z`&?tYTN6s3Ij9G|-1}NTDed5!M?;8Uyb|J7AdoujXy>!VN(MYnA-JOmZabAG!*X2= zM1#@B%U{{n7rzUsI5(Cvs|PYJ2UHoze5rM6)$m<_VYJY*%z?i+W^VTPo<nuhC<@Y?V%i$YYNqw6ayJgk_HfiqRbN4f$7>P#@ zcqln&3>n+OX<7!eR3PR=uG}}4;Ugm{ulO)lANT^QV_yC?DXYv0_F5VV><}TO#hQ9F z>n@fSaHs}uCmzeCK_{AF{jCZ%9iA1aU3UE&o4E(63a#)e{;bD4aQzLn-(~k8!iE$M zUeKcbDE-St2$PtyK7IJ+PBp7cgbojCEYk43Gz=Hdnvx{Pz9HwXFqRL;HR2a8s2V5P z2E7*f0OPx5J(NELM#}kjq0SOre@mNBi4YpVXH~&yA`fo2>Fqjg=Q2@d(|{#Js_>1x`5hF5*w#)| zNukM`D&`R#QQ>R37biI|oRGW+M!p-5G=_B3C%q}M$5`+EAwYl#-TM-Kc!9%1EgFm? zXrwjjO$hTzazm?yOa5pMwyDtdbyfZXrfC>gcUg9n0Ec1LAKu^D-Y&U~ByI>QCcpB zNELn|RF_G}c&YuJ@Xor9h1xO8cg-%-roMxX(=Ke-WqKIh^~Ak~2IMVAfm1(p4ZbTf z9GYoO2oJy?#}fJL-@5t6%fzxE#o@S=$1Em`@$`!lftk!Nw3`oF)K$6*Qh&k1wWEbE zjA!5)lU3jcH2wK6M<0W1_;`SArDa(jFFUh7_{9ej4bK~8>_P_$In-nIer4a8HFfop^RpohD%eM?Q*`@m?`4;^l7Drx0#neUERf}Em?_}L%OmV)HkU| z8if|nloM^u7&(#JGmDI`ClN6+m-z4#qM9L`7uVx@1)EwMSQp?8L>f@&KO z#Bp0OUlR1Hv|VovW(4VS?VZSZ&N5(Y4?q~i&tqaK{EI0tsEwj!9X;iBvyQu-h#R@V zIuh2xEms-nUbMU}*7yd2Yy7Ol`pzzo@L2p&`Yrr!&Gj2lBtdoSqA7nnjAG4b>}qvH z1B|(o4T~T~%{B!yBs(GPLY{<(ecCE{S`@Zsm65O{JhggjTsS%zn@2{pTAw-t)!Tq6 z!ax)||8pUPePl<_HQpg3OJ=yrCaga9cl_?if@1hW0HTXYqH@zsQ{UOr_f^d6l6=+D#rX@5s+mpAYTp5IKAR;uJwT=DvrTWaPEtC7U zU42DjJ=3^=D})g~Hnniz>|=($5pf9ZC_W0LAxmk|;>m#RE^K-oO&ca_y0&gsI!)lM zZ(Ifd#@FY%?DX|t$>&8`Ya!e$HF8YhF$no@U0YIIEpeaVWhUY-FhQ{GRw-PqB}b4g zDm=C#-H_`Z6XDu46EH>kuSR#payH^8uH|Xp;ni0X#Z;m*#d2_pL}sZ}80VZ2B-%k7 zhA$v46;rf6@oMBOie)Jh;W71Zmg{e-S?nSu?p=h^ zE2+#R)kzYB8MpLFR!r!_ZJjX6&t_rMAzB%TmXve9fMF;o!B=CaxzC=yAx%XQW9F*Y zTMzX&EL6zRZ8uDXpn6uBvex7mfw?&{GEFheP(l{)J#C+NXaNKh#=C%dfX`i{d&iHR zOvvnuGd^t&`+5jE&_l2q*zo?mj*UjsC%ThR1XcXg-MZ8atMFYz8k*4U52C0!XA~x{ zj*p25?a|!a166UuXaa_eCk%eSWLgY+@!XrgNXf8uL^P&~c01}!akZ`GVYxLZX7gF) z0jQ1B6iFz6sW)+&7V`tMfhFSVsmdGYJU3+9SctELxxGoI0+@`dqfO&Ezn3pUH}j0d zRUw-PkJ49|VQg*JMKK-ga6<4t3j3|#=3U|GCIs%7z^@z8GHt)2dB$#P`e$lF;Vt4z z6Nf<!5RMPv-lByXn9k3c?+jENjhYMVA)c0JC{{lAXAi^5okIW@zfA z#G`geWPne}?P>(>sZ)A__?-x}>fLit@UKjaxA(Kj1Lrg~{rF9w2<%Rec44qYr%-Gn2KVG}}V0?UEDR6Kz&nfgd9 z{{(b*q?)Pr@{=~hjeys1T|+9nQ3FCeJDJH(2jUz7m&loJA!URO}aKgRS(=z_?f}Z=sDNZj0jkG z81}l>GQ8)=N8N;@&L*OP@R+)-X@0#zIjFXgiOL01@6A~ZmgpO^-xcyWHK)t90%G_@ zO&d~v?BXXny7jh;_z;#Nkzeg~2W`2RKS1)DK^b-z2*c&l+eC4Uw$kS?-e@5WKIJJs^Cj;mnCKokr`PRUZlIw+zrKnDA#Jc|aAH?8{B{^YBJ$@5l^4iz9-Fq< z9+#y=ryTw<-d8cDYH-(yn=Gfs+iGn^S+{2-u?U7t>6=Y&Sr`vlZyb+IwtWmz2RG7^E2oYBWwj@m;Df8QWtNaE+{}%8|GRcUTbNs zfi=vZ`3-ZvcK(~A%6>}xs^YTEGIU~Myd_#BZ$MlAj5&2I_a2{TFQaNBMLAhx+758a5x zMg{qstQU={CjXFv{gv`>RLCElPDA=QQKG~~v%+f*pc^{oH%ao{g|G+{D=7Db8%xRU4S4J5W>pkalIK!(Z^ztHEt0@a>oN* ztsg)q>TF_Ot@e*5tEP=sLUq;ra1|*?hZnPUBl;_X4ND|A(t17j`<=Px5Aws~5=;>0 zP2P6LGbi&;e6tKmiv+Qz`pS4JxDVXs`SE>Gw(Hpm3g@#cb^&swn>Mzd?Ps=UXrNcD z+qgWA;__yKn&>xY2nXL6_e)2A^phpzjbS(a{vCmSk&REC@q_|*JgvtjGHgF$GF>&+ z;$dfVnrHWb4-NuKo|pv^{qCbi>l-_v;*pIc^>c zPa0-Ce%uU|crA;=FrT#e-ED<=-Cha4{V3Nj*iqEf;vjHTT5_`W99wzloHs1y()_f9 z3zFixkL6lE2YnEVd9We3FnBPF86X~S1agtF0B&X0%181Bq9g*qwV88vhmc)9gHKu_ zP!TEyP&MJ9kW;yGm`s9eI9 z`>lKO8BY&i*cTN-`l@V8&oXR%@4ZjWW%hK7Qp)l+l5)ZbsxMv4n4ZStMY|)deVULu zt-`}W2|UM{iQU&~Yyt?MVN@0N-=4z+_R(Yd)m~pUG$A?C%Zl*SmY)&$YC>#pq9|~v z7~9JnjI;}>T3@%Bi)S%I|CcmB?Q7#)WQ%1F!2vpw-0a+7MYch^m z<4Nc!O8(sw+kiBN931x|Rr9c_@e3;hy}L?9Um0HkHW)%6Gyd`>?X2Y4L|m&qim5Wh zh)J~{wR60&yPo11Owde2Mx1+?LBQ7KyC1O8ImKRwVtWTT$fSsXO?5XZ$LP%)&19_y znE@obmbkU$=_}FfVt_WE7RjiT{gH5W~7QvmirF*=&MUT-u5@W5|#p0tzc4W5Fpf_vKH3`-bTvANS@ew+4;RD z(G>o8$#^jM`W7X^&c9N8en1p8SiqqcT@@IfHGFd2K4NZdA7!}K8BcN4SgsAkn#01g z^zP_G>1G6^s1j@Ndozgz%44NHbaK!8?o~7XDWEWe_^G7K6bkGgqmxzxXC)*gicTYl}V$(s^ zcLR%iR(W#`EoIm$2~`#5BShgmv9`kg22&peWw1~Jc^FvW(p9KU3U~bq4;i5J7V)#N zYEDxap-q|=i$n(a8DH32z`YM+OQs}G^O3p1*PVtqP_9WYNJ`5<#@d0UH%dy2+c>5v zxZXJ%jmC;tmncHj?r))2pqVTe^eJdcLwvbb4@X0s02N4PpifDAT1+&8&pehXH?=JD zbQ9P7=S?16Ld|>-8bW$7CO+0o7;*FLWcvgJ`|+Hdf>lf5KuK{eY%P-#4dEX*!{vVE zSeNla@|MP+qM+vzFi%N@dMeA1D!F9VHHAljk+GZie4+1n&Bn+>VP z9~jFtG1aIgufrRd?a2&@M>wC8*cgy)K;$bBSTA$bV>=o9jd${<;(em~0Iy4O<)R6c zz8EAxU?F;rj2y7BROc5UEXxG^Gb7LLnz{*R%wDZ1S2f~(jpV)g;We{5XhR2`AQhW$ zQfq_w;6(6q;uShvH)gsQX$iyJIwXpbC%WcdFZWdwAShh@duMRWKR7+S{^1%kMW$tG zN2ne-1#W@ZtBcfL0@{|Z;*&YRUP%R9g<)ppiNl+E(Et?N*eW)En5K)nehwtie5tXO zdq)YTFaPiB^Ij61sq#O-FHCh;)|%Kcumo!fyOn(0!}&fa6PSdm)aKI1VgJM?p%36P~+TJgBa5vxW;dhUqy<=P4 zW+C*F^lc+kSr=qR4zngBr-}Mdy~an}2~9ZB(}*4Hawt&oBj9AEyIuItAk%N1UY%?^ z=-2q`Np^#J=fJr5vVuWgRDxvZ?fKFj$j_Razda|83&AJzRy*h(ZwUMygOM-Z~w> zO#nDyw|2T@5=E!<7rPz&$Bu)SE0hs>_l(xKbrXRrUZMZaF8b^>)I|Lm^|WDX%<#C% zvz`mfxtD%K5A^xHc_%^->}~mwipIOt%|u@)h$`AuN}TbxI%_S8K-%WGW~j;Qcyg7l zLGKACd?*rZBbTg_?w`|u4&hGt_)9d=AAqDZ!w$9ytbTJ+hxn(yimp&qWL zstWB@jCHa6(HudYQaEYq%}Rc>oeYPwcC_6T3?OPG*>&rBhN@@SiiU;PkqhE5A2szJbifENudF4zs`VmHmC(0|NT z`ny!l2(5B!WyN)=@E448_v>8)yzRRh@!mhT-rl2+9SyiDPmI}t9US~~?CAr_W|v~yI7{_}1Hsn(XAIbWjxwr`U>>N6RnJHxS4ef^7{-A5Z z`^l+x*A%qME1S!%vOm(8`Ii1mvTC6Pqnz}>?58w7uM#Quo02+x^)wjv`c1679Zw3`Itx z)RMk=3p;(mD~o=GW?iUF+bSKZuxbf{YZWQ?x%Fs8F_J%fC6I1ux$Mf()@e~{3l-yKh2d&(rE}c+)*?kOtP)Zy=HDPbe)DH273Ef5c-ge_+xAD{^6)Dx z|7{N7h(IsBPujR^CnIK+hRF2`@AbNQn1y24Q(-2mf@G0`^Egm z*|+hER2OB^_zRf6=J_8!HgBNdzWe>zfgvxNpn$OP4?TFLs}K2vM$mC(vek)Hsi!?I_bHibJ_=WGK?m!b0Tj?Jewg+%QLIk%*#EG*xm>A*-_H|+~+J!H5?Dm zyR(Ll<^1rKWC{zP+tDx%eKg|{jC%^xf2*omh0BD3>wI7Y`X635HG0v(?yamk3dB2) zIOEEO&#s|;D3nX-XiVZ7k|K5Wp99clGb~zF=-gCiiCd})La#2FTL(6L>+(ya^{e|f z)4a{7$+*RN`M4?E_v|3GP3x_W<%(VUi#&nSWa$zu$^CaNqqbf*-mzxjK|F zwR1}F&uAE~_R7LgMN3kX*O(d%2v10!ctZhs1LJo#@KwRn4wj7DL*fG@i1C zx-&bp#$`8n=SSEUD$KaQpV{2$CXL+vt#wYeOW5i%u`uOYo`1#A8eunI?X&yv`ou(E zsmyxMtxca&wa;@+_EmE~=C4`teXcNDmZN)ZkOJbocT|*LFAPb(f>D5Ve)pz^4OeI8 zF#BB2j0t6W2aEGOB(2eVI5GM-0@v(-3zTTADt)nb{PntiOUhx@_0KTkw6_67SoJH? zl8L!n#r9x2+psmamg!rE)Wx%V$!61k0y_%U@^>zffv@WZK4#ZxJ~Kl&^>U%gcOa5V zb=I`>o>|-VTQ3z(b#q@d>tBzTZ83HwW~<4NyG}JnqUG}g5BN9lSPU$Go9Ife7^L5Z zDY-IQ+PAYAO7yo8&p7+fJpeI!HzHUp=MLAsK-^z!A~WH{otL?bTg4v?%Pb_>+gABy z7j_d4Yte&yWau#B8$`f7d#gwOO6+Sd79vZ+*w>6H-9>AzdjQw2tSli6!Rbt-} zv9v{xJ5#T_C~C1z%2my=PTStnY2PPyb2D4S2ISxFt0Glgu(Tglqwe<8OC9$~xoeeX zB~2JnRW?0)wS_E<`zk8v{noQup{J}os-(+Zu8)n4 zPe@BdQzM7doTL=^{8~gRytLeW=;g(ms{Of1?k8z24IaBf7qn9f{mu7MgiqJ_i!4>8dK&Xr^ljz5uO%%>OFg{}vus z>-V-MWY=wT3`KbTGqwdj;_Gdnl8=bl$@$1F3J{znMG0MzkZY2_`yRbe_y*oi=2qB+`;@3Yb#A)KM+A+}

Z)vT#(dDMp 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

S^^Hb8?#>enCzf|V{91Wi zgULB#Mx>}q@Wy+Ni7vKQFm64j(2P!959QR#!*pclRnQaEg!+-QNB)-@EmqY|!$O=| zd4`p4Qjf%DJJvP0@FB0nI#p5rPS}zO;3M#Ee#}Nfw_L}fPY>YJr(={ZfslV=Y4(; zhxX?DG^F_3Hoj7QTG9Vz(6@Zxk0F$I)vGSD;}HtmuKMQ)8Y)Lj8<{M^&VxIgq&DGa z&?!-Ffg4t7yfBRK$8TBZ!|fT9-QBUeuvU8u)+$omB({>r`%I6icN{w59Jy00Gl>gv z{>d><*~=c*^Fa~4!q`*Vr*sX>{(B5XI+U6uDik(iKm_WpDp~HVtWfh#@jP&ECt!;U z?L;u&*^c^|AT%kM9c>#o>{4J;-&B}&ldNFh|D<6iqK8Fh>1kdeZCp)mr5_eA#zQqz|_>xa$3Zq-b1>QR5S2$vdSWf+W z1Dd%F&2)yyoR>c3J?(XgHb&f$A^A%~Y^}UD3|IrSu>YJ`gMN(5`+Ch1z=k-0fi$czdkG#C}l9P2n0RQ9%9ID?O=4 zUn&_-)zA>ykfHzUCb`-8-pjn@3m><(ZyUybTI+TvO8h4#GdUvIdhZ4A7zs zuBtzJYl;|n>~=C#QB!U1N2XGyc5-2#Y3V$7DlkoIg0;!kIfUk*$FGIL18xL<$G7el zXbp%v30nB_Z1y!OvAsHY;igtbfWkJoi2wJxA&FfHSm*OfHW8Hur9v(jC^b9Rt;b59 z%|O)#@fs?iY3Cai#X(JwIN(>UUn^GjOopv|SsTjWiJ!Ji#(IcIto408|{Dvoj zr1s?mEDc|+gzcX*+`eD04Lm+QbIq@aNB+0>)!d&#K=Ot01`lgE8`U*+OB$FR|2?(f zWO}krztBG1Q$+bp4Zs#6vEICWQ5-IVZHrZLDm*GQhp)`=fDI5w3L7$z*|X8iS&6>* zqdn$7%l47LU)qqi^kR_m6m!U9^WrAs2B0-ql&br07LD|}%dA-$7(hqv>sqeq9K$*n z+XvjcN#9C%P8kSQAZm;$f_Vdso#Z4?YU}$plu?%OG3&O1sqU+;cap+a93O7&Uc#>T z#$ri}j1ow^N!aHXvh^kvQC4yXs?|4@Flr+01@o@|USKR%0A?aN9oaI47fxk`Bgy_} z%KD6B3tEt=L7WxXFb6$Eyf8hElXy4kLPdl**5ejQ5S5tU&H-EE1~#((=ee0_PU`uY zfjSDmj#5A`pF>k!8zo;<{VP=arFLl4|Cd$iBU-osm#kW|#3<{(L5jejZY7J(?09(+OKR+U6sLe*(E>M|O}{kI0|WSSm9OOZ6# zIbRwQ8}aek#H6@*WXNyu6YGp%Y2qB7frM~bkFTLvRN#m|fqWX%pAp)+$nQirLb7tO zUb4w<{Wt10ONzwRK6kQ^2b#UEJ+aC6+;o~JC#OO6i4_aZV;_r97G7VGY6+)1X~?!d zI)|n$0JLPdy_1ccEY~#ru-umKMPqaQ$P_~kmtoTX9ibEmsuTVywX%p1_^7Hwuh9;I zv1HZef76XqTR2yEOec5A{l?}*T2W7*Vv%JfM>MQ%3J_%5C(P|QRq(tWM|lhZ$J^nP zwA}+$)>t?bkX_Qblcs|Q^ z^jK3n5Cd@dfL~z;9Q9fFo%Ovr!jkmyS}P(^_WMZmlEZ!^gatVwA+;ccO!#?%e|v2iTz*igl~$z* zwpjiyTh46DZYzW8*PLfmXwypiO=zw{ty%{G*pus5~KMF#u?EY3dj*mw8~1EV;!5F;~;5YA8}le*IZAy*=IK)e$> zsY?}%u80N1E&K*8T=^zVSt-XS7wAE<{R|3$vC9&6U-cQVeKP*zJu}`Um=f>y^ItPi z+YyQAzGO{JdR!$q6a;fMDtv}?i>z17T#ZLlYZ;G)mx9K6Ao0SCjCSAV8>d z7F>)O3eq?agW)6&`4%xkp$D7(LH{jj6jEI&<9Y*eJh|l_d-3M|yYFZStNNr`Vprtr z0unZYZFJUP=L03Lq%h$tl`xj6oz-#ww^c99IjzLjW;-+A^?q=b|I#$Qva^oH@3(rW zP`kS^2b=F(`JAh0w1s#1Vr&cFOn&=`ErT6t{rrQQjH=D!1|gq*h#6d@_-~)!WAQED zuB#Z2y_}CqdYmNKxiNr|VSUmGN&&4^MC@U!8+XjYG7XsTU>wmTubuUVcD7J#<>YTV zGL4GxVg0Y?!A4RW|9J*gJ-I1wXAWX=wi16)27i7a$abMe^`q~k-m1wewnlA z+?zpPd}|Ny@CW;uy)hMkvDP4?D{C z`__4v>6M%8Q^NKkOlQPC`x|mB|9^pKE|X3fV%Ie1Qp|95phdPZfM;`_jI!V&n_Zx& zOWJEc$aZ5X%HY4qMoe<|btk>0VjKQ3K79NB;UAv+_lsI376#ly)5=0^Yg zyz03BoY;Lbzj$sv`)KE6N^5C1KPwlhPA2u3e#xy24!reiAxB&q0dr@E!)~MnM@cx* zS+(A#*Neo*T#x{F1wc2kT*vU)*#`*hn0oVGY^lj_9z-Sm5H>VUX>067s2Fi6l=JAQ zRKuNYeNmRsABX>}2Py5EFEy(&LP9#w^1hN3Orz`}l(l*#ot19<_d5i^Dis+aKAjnV zG@2rm7Naey zS&zwCnc4p4%{(E@jW2m~Dg2+m8*nxVc8iBEw|7c^Njx#O87S#zz)=~0Rhp5oi>4s` zUbxxHC>a5?-e^5TGHoV}MTQz-{X<`dMun~eP)E1Pgjr5C-LqbTgKyqTv!(|gOq?vf zUn49y;0oliLrEO##rVTzY?(N0YT@gm7v9|#%1W$R$**FR4TsFER(jWByRnJo*UWzY z4A~Ek58hd2LSTlTV6a|ssn(=3nVy<5$Z8uB8F@LN-NspC?MF&O4-_OZK3MKk8Jqbt ztU+<+iPu^#p~LFJjc}cn4{e52l!U+yL*Q>?hORT18UbkcW5JyViyZh6Ap4R7f9?at ziHyRDcjFHBmBFtHw`Wq@UvGD(crSPkTHvrNwSG9}sWXASJ@z#YrU_xrbg6)?R;TtX zR)8gRPW94}c}tnTM^%?5+d9kl*Qo8MYYM+)_qY|WG@cjZZaM@ITI4aq_4cu@eORu- z?UM)V*Cb;!0@ZyVGdYWqPPb3m#Y7%LEKl?J>@NL)4602|4yQ=OXb!x5LFY?7LqUHY zK{)p_OglK<$2SGA>OMn9bv{RXWUjwsE527*$d$Z!~$&JH1aswff^( zPaElbEk3~+9WoFnuS__XFO$-x}n20kE+7BLGT@x}CPJ<)C zUPdl|Ij@$g$MQ&xg_$vc?sptaOvN+=>B#l^1O?~euC{9>>c0B)SZ3uxPp};BR-$@s zGX30lMnDpLr>rH3s(_+ro$qR13Rx6|!pjT!*p5>-3PledqG2Uy;QZsJZ)O4}=(Fmj zSvWEXiNGN+|HmD11okrn;r^gZgf=LxWc++CL2+;Tx+#)J2aY6`CPHmpF_XO+J+b+3 zqu~|^?DmW88~oV2FBhHSUj02E2X6eV)tY1aBJ zX~A22i|AEIKlRzj^ZY~T1%)maC5MxEr4%|;85JNkKR5ypO{3@wCVqumJArY_lV6HJ zN7Rhn`fYg{5pj6ULk;aqU6$Z@WWeC&m5TvCBxxgILOi~j{3YgH6f$(px-ICsUD;9I zBiscO8i!O@mwW?snMF0A0plZ@%{Yl7D_lQ*ji+OgK&Ai^L@^!dvJZ;`p_ zIhpfR1Q@F-iaVo6>=k3pHIO)FlGl_ft_Y5Vn3Q~bRPI~;cryXFXXP-{mVED69h?Of zKTpvi*VVFJoM~m9lByPVOI=IbEEywrWYbEWv>I~w`^$8;3>4B?ZrbbRA#n4Qs`4mnoQjXm??gqZgo**~ezGLaSw z*S-54Ytq8$W4Slj;M#1h&jv9|FT6K-Lx|xE-B}c#e6`x$M07P)IFhGz(@wm}vVT=j zcp`)2#CDiFf;~?o+qkmr%e$Uzi$BB$BpyC90u&uQ07S$d}YXxEH8 z??ox!PorI(%$AoLC>Pv=#J|{&YQ@2LWZ`^MOh>RhNbS?aHRlYTe%`CES zp@b?qYx{=3MOv*?3S&*G4wa!#=lCi&$g#-N_*(isA}XMX-p}gowapX`{1qECOvTlk zuS3qB^YUS<@!Zxe&My|4yr7=Rkw@)GpAgLk#bO$QYS%o@#zEeWDf=TJ+2ZTNEge1M zAK4CJHaq>zoIjxD0(9+God;ji`-y7qWoGo7qU0hvLYCNW|AU)DUl_eke3fJ;ZE`k$ zet4C|4KJ}~VN7+J2si5*`zRoP$cLZzcMUgybWXPPfOmV8-v05E^Oo{RHL+v$4#!XS zq#e`OruEn?$?V)0bqtOSju4y?k|MmBbc#SuUx1HW7$!Ut|J4$AT;K&HmOFDJ*(ES~5*kQuQsBs@wB?R`9P;sE z9diHGqq0mS-94qQS1yH3eCijShy76G88g)4V?%|>vh}OABRlt*c#)U-y^WZbKCX8) z6-947d?)^Sfw)m@;~Bz`?PR@}pdjtV0~~L#gi?^KLXvir(HM`VAFO-qrr5-?8^Nn| z3TKgOe}vYQQ;_FRbRwv^p7IF+H5UR|Vgy6P=*D%!_3PLdYM~OD5tX;*8k$G*<5 z#K%9zy5D8k24oJ3Y-W;Y3oyb+gQG?y+BVQtR2HtUTPY8C|AJAa?C z?&X-mn;>1$$J?mz(Dn4XtQ0}NbBMBBwP=X6eS8)Kt6e%J6MntI%v#)S^_jhwMSEGc z7>TOQ=4joSQjgy9fr8x&*;TA9aPt9-@-bi&B*dw1i#HZth3S`dN0gY*zB0=iei+ z_Ai!LcJ&KcSy5^U4;o!NT3IZR3)LPXDz@-~-x3d~1oQ2w2 zl};~Otz~aL_|#!d!1i$8Jm7~|W5_nj$aI3Iaa8sqx8Gvnr-~H&bgPtYTnfSwsZDHo#>`=acLd3+qEt6b@NL&%`kwMX80g?GPltMCSoq%GgPr+ z;a5L|x4?h{2Xv8?Y;>fg!H1q)f8GT@rwOFfUHynyNr<<42nj*fm!Iy`F0GkAMSVC7 zK+=r^YZ-2NWtPtNJqFy^ICN9j#-Pu^Cl7pUcdq5@o5aCGRtx?pvxX$nO&c_LaKUlY z`OfevDS{Fsv~sAyGPH9HXwitiaIg_C}?bd#3~Su zo8N$puRhx>AX0djENZK#-s}~7s>|jcJ}m!;ryw@lVfF--nj!do4Z|1czp`oZ@op|8F{$u zez(D#({)gB(NMWg`!Fr_+Fyw^-5tdp3~g0|x*-nyhkJiMYRvcw)bodUTtZ`3_jPqEO_@vgmSje49; zeg@TP=}mrvYt1-&MtfRPbLOkacpG%wwC&|C`5j+WmfDL|M6h`%nCVeJ?@7%CZ)-AL#6P`KcT-&+?<=5G{PRxtM z?=(PGd>MOkjMeCPpp^e5kZ4j(N%(fIaML|CAoP{p^|Qd7TgJ_qiWG*zhh)7SD60x^ zM+QGWt8pN|{RT~f#G^0FE3lcgz6r1~ijV`GfSbWM@e~3ZUO?r!EmX8!Tkr9~f*TOz zS_Jx+-ZCC$NLL8AH+ly40zJ1b+%%H~k-7?&N>B^q*I++^eDljSgz{rbHfDsM!E~DT zfd%EN=3InONPJ?22W0jU2FcTzTu^tXMbxh`U)b+j@z;yJc?`ily6&?7rhMxvz~KEy zrk(f+J@^FNlDPK{h&=Iku_;0D5{)PVE2dw@KzjU6_`0w9dq2F(%!7QZ-dWNrKO|yg z;35fZt2)vMQj?~F-bJb%EG14wLuLy(UjWX}mh`9`3=@J$PvM zu1Dr_WB1aYJh{!_rc9eIlH|97nLbvaQus9YiWc6Bibn={_fjdN>BOwM-J;f)r<;#p zHVtzIU6h&@UNe%TAA?QYfyscEj}V3Kv(rqEAXviuEnYKSas&uWXCevL?r)1c;o(8# zWKd#K7N3L~yv+Sv;b)Mumk;~Lz~BA4`thvn#$oN7mJQOWh}Hbg19o=A z2-e?nfQsia7)IMD+W+eQG&!wTI-^6tBFNv>n|HK$&NUNP-VchF!8*@g-L2oHGe()b zHN+nhe@xlF17r)*2jPm!R}9~J5Wl7q(JE7+O>1u}G}k&koG;obG2zcs5*(5FFOamd zyJTyD;4c*^N-56fp>i}N0g8@sBwomGo&k4iH2Sf!v*~ra-%?7774@qJxqE21;i5GQ zD6VU*T69z5G^DzpnFYihCYD|VekOH+yyCF5&%OTGXD{g)6Ywu97Aj5ij&}$@%zgFC z^kRtH56sT2T-u@PTR-d57xazM5w|X3CHA3l$P(FhocT1IGoai>w((y)!r2gb|hh{Y29vHpX$(~BoK6`onm*4 z0yvGcGdfk4UB20O?%+F6_|q{#6oib@bpv(ZTgD+EQgP|&b$4>A)vgwIZ?R1Uhxf~s?UTuMF?qAZh(2m=1&B>m&$m69;1*-<6th`?j zUeA8=@!FyJ#|MJA7tfP(>EWv6&;GuiJ0_%^Petg$;bN~Db{wqMvCD7;!BJ!c_qyBi ze|9B#qcso+c(DS#y?vExstvRGY)XYIt_RVa2qbxPf1_LslN09n?a{D`_k7t{u*Z70 zB`a>Tf+~1lf9CW1hm{Yc5-Eef&f7;@|BVgbg9u=03(ZSEp3NQ>6Wc#Nmg>ZPcW~@e z@P>_^wl`;$gC|h(`BX|XYnRY18S^%<{dP%f9H?zDQsEht_dkH6){-Q%M9BRi$M=(>U#0)4xkWi)O4AJ2ttHPbn%bWMeXsz~|C zLuJG0EvXMrH8@uBC~q630%`&m$L9X@8XYiRyQSL!@d?32UgYd*ADdx3z2y%GNoBL$rO!P(-C0AJ?A7v zbEMV%(r@ZKu!U3NVq5M5rQnSH*otWh9O^Cfn)-&WUKq{qt_&ADK3rFRN~2P8s>9rL zo%_(X*scjaq4nTr)sX+C`{_)!r{`ezyjg{f@unO&mgs#mwik_Op&zz*a#s4v$u&mN zrF@{qC9>kO6RF;O&xI~;a3*!NiD>Qh?*B1$)nQS6Yxm4Bbj*N+C^3|@2nG#92?C0M zbP6aa0@69mP%;7%O2|(-1f;t|T0ly=Q@XpqJC zr9MSBvQ8Z*#E#$EvmTdty&s4qnv4BxNj^iEB-cNUg|C2{v&`M<=@AL|sG;;Khgb0= zEI5~uTmDH`MgS7a9Ey%o>PbIf_kzS_10M=aQS+UZdgZr|APR8%(8K#40n7PuXH5dW z#xnkpa9i^5Q(2D>K(b^KA;LdP5i?L?u&QHoG@}UjEy#_L4S$^*0fbA!kc3Rm{U6T5 zbBMxNQE4y1a`wSuLN+Dxj0}|{a@fi|vKXoD-}saipzK|xRj^!VG_1hVNi4LVBGM*9 zFY_sYKQC&eq=fD8fo%`<iDuI^2Yw~+C|~{8QAY%$dK&t?&k*} zmZs8YPxXoSSBZQ(QrUL;8s}p(P?fEE%eeYBC9%nAe++}~%(Rk4+aUzk+*vB_DFJ4t z5Y|C`29M_xvw>LIYziVN{W47$5nA_@H;WimLsaDx{=)}=GG{V1RVjt5gB_ph*7bO( z)}}DI03`1k#%guDi47GA?PS4$nE-aX#RX94UF3>ximQ)0eU)ZaE>>}}?!ds?y`B0E z!to|H-MeV<(@`h0hnKtE#6Wp-*;<_5`OKms>C(GQ@)_8SpG(z{ZEzLKzM8nyOa5bp zdVR~u-5;i{ZGR3A9{M3R(IO2HDv=S&J?Z1`@QTEqSJy<6a1>*&E2*H7kZ!Bfp?hED z!+inE)G+wk7qCXS-V+OGK^!Jyj#aTP@?YA=sTV#o;?MO=4u(BV%pFbqsQ%m**1oU| zj}blcp}ZNB;KQz=V)O)HHF*g4=h{UbXp|VOqR9x6XL;Zb9|A)BqD2N90@~ZEUoHSM z;Tcxu&kI#9`SA_9{3g4MQ^BVqv7)0G;#@)ruu7LG_E_bl0pTlt9vT3ygoix3gbI7- zpf}^xJUAFku&NNrQG^JH?`%#24gC)0u$xKPmXD~hZL%xNocVi}c?QV_+c62ndM}}# zmki`XqvxB~+g#nBzF}M6DttQ;=T*b}GJ-d^ojv?7`DTRkOEviV!=hc)-Bcw}=ci8Fu3A59jDtx`VCF+1QzXD_vfEytfh!6Q zk5B!iNWa9j&ip1N7K#*-S^8PwNr-bLw{q%FXW85NFM%*N6IFE|pwanVvZIp= z@gSEn7eDW{d_#ylHOw^|{79*rPxjD6kF)&%qIA47Pk1(sj}1|DJ(%%BS7Z>C!b1IS zyf3r%`-kLg$@R<-oiHlcmwTd*w+AW$-JQyvGTF^;dPzM*dGF8yY(m>H9~L{*8-9+< zbCxi$oDKF~BC6{h>^L12ee(Dxgt5a!W*+1lS#_^EsZPAR^h;XqeFixAx-1nxXaBJ8 zs}D`NUlS5lW{*}j1mYofKUJ?cwV7~#Eqxw{xO+Uy$UnCAZOl1d_8uNG?w2Bf?4+=W ztcD1TpM?&@-33w>PvIq1Ie`hng|hyiGT91_nZ@Bt-MfV{H|~~*S#ABU@&>c&f3v6l zfE|8}yX2@XzO_suEW`OSu^3;P8j7^_^#c{7Gca{&g3v~>DaQ%hUJoVt- z^CKDicv)9cKP+Vv1A%&pNiYfAEg@|8sgmXRZ5UluujEE(u=T9MFU_{ur%+uT$TOq1 z+RV3RL>zqWTSv*Yfj>)+&W0{F)fI7J#%qbmoI#(HiY4x&^06svKm;LCPpW6|a#U~6 zDBTIKp*d(2ys*4HIH2H{Exs}%H8>VH|HyOZ8r(`CPX%q>+mfhQGGoX_Ni5M|1k*U znloZLJTnf_Og0X%rdc?V%!9m@8LncyNb4pzdc{I`b}Mls&~rG{w7+a&cFCVvQ}Y?~ zNgEgQtt&>@Y#gyo_Qr9nuj4v^bB!u_nmm>5v2lJp5+ldCyXIl(QOj<&kQs}+}fVc z4Nc|7MO9-L`<1xh-e71}6nRygX_J^{#n}+>NMLbNkNer;;3!F9$?K(d1`!QtG!u=mzHn9 zn=eO9$QQi2KZ)Koukfclc1-3Pe*;B%5ZQBsunM6d6|^FmziL=U9k=2nv-5cr*#x*g z?6d)*`f|VjXTU~<6JHmEhr5tPV+x-pX8(jqG9r7#pq->k>8AMy3vU!3xqmlSIFzAl zSn;hpdr5XKNanq7p3Bg2-M_cEpJvx)yc57ZjC2MvHWp@&24>Y~6&+RIR70_mHfLuF zx9e{mf!Or0Z&ZN#Mx>7LPJ#@gY`EfKg8gFlw%>#lm9qNP?_;{j+SX0M%-FN(+btXq z7Z|d44USK4<0Ba`5JfvuRBHmw+Vh4zX!x4Aniu9pC8LkllSHlkIYi0qEY`BR8s9Ysz-Iee&Ms0dG`E=gmiU-AdZb zfk4kgD|=)01bS4L2hfifS61ALdW8AO7t_^u1v1Dgf}k4%(r33)>n$?9?O<3dcad*F zPrZd@bV5{nPc$k+x}$VN@pT?5oPInj=w9zlMV+Ur>o#iv{&ALDQK+d^!gh;ev zvqwSmeLV>3d;}{RCM74V01%b-tU}D@zrA}~>U3i{>azznvs+)$bZ|$XKzjdMTus8( zr3iD3p4PI5NXT`!tehLQ=@*nLigvk#NKg6**KNOwy1lf9u+gF(p4?=L@Ks0({ntU* z1?bHGUocytZ}ZmjFN*Ndk(G%0uOxipZdj|EaAEVQJiN4{%ibbnAl-svs9sP0)mg3sH1fS1gF%lQDq{4GrdMc`~_&MN*pR zxF&?4M8~IzP(xvj{Z-ZWSUVU>m>1)GI2*u(_9$9tQ*!l6!tz>H- z2L7&9NV6scQ4cp{7BF6|sm#j&C`BuTp}b6;K)bJ{((oO7W?(kf9+->2@j{v(m~~x% zXh4+iYcCBx?){+x0u_cU_42f@sS%;RPF|*TG}5p$R}bFp@k!9&wr0s#sU z9-^Ia%BrwB2ey5%VEv~>+CM4k{P`5^zo-}gt_ukAF#fPTzPA(K%<}y1y~@vf#)t+Ul%EOVA2l(`TM3H8s<(o%N;0bGTjJqO9>0Z)_BsJ z`9BPn7SaLv6G@7$-f}|ZQRtMAkgGc(E})6RCR`7L5u>vOE%M1 z@U~~CNYeR+L$;j75e1@NO-vY%Y`ywEs{r=>8pZyc$1c9f_%IYOyR}&*olh+J>HV1m zDicEsM+{XGwr4}y6QwaQRC~5ST<7^YBBx*-u()VWJ^MnV4I<^ zzG2EkJc0ulaX|f;h|e9&#tSZrdH$apzN$N{YMl{Da@8fheU+J*!EKd}w?F_0t)0FV zNrBdcshLe0y&RYtg-m4PV+4L{Hd|h>-CADQ-NR@DX7OUHWGj-Y>rxI0j;4i7*tafIh>|CB472tEu$(U*w=$n&nDBUFH8u<3~n z(C#*&g@04goBPsO#9fsXz%@L+B0IT1V1H|q5IG?iO)L|1g8~&QAqGQbrjvkPa@B}q z^;R4@c@l!#HQ9m`xu*K&&0hlS!o_u!=Z{ksDY>#z3vkbm2w8we=6BQen2i6?TpFYF zEs;WQLWJ(hUp9v6PB_O#{sSLsQXzy+U}ncCw5R`B>-C5m~7>$0eDh zq6JKQW57z$l>U61Qg={ya*xXU{C>VMIW}!?-a?l%BienE91FuD*p}6Y2M-=Lz)-Kj zoG)?}aM$@4*YIDD3taWD@vnE$(pB;#KV<5fet&U$ZjmbqDP;*MS?4T?xk_8tccj z0Aj6O{W|isB&x#2dy+Ba0Nj-7cRVygg1sVOl#&-iQQLz11p#3V4uBaW(#c_m%(UQ% z@ez=v>Hhjj3LYQnEd<8{d@%bfJ?My0d}njol%kz?`uq2XSc*UFk$=CfI2jwlrU=te z2r#4iL3%(Mpm=LJ!K4#{41_fNTbuoWM`N@GvP0b@dj(M<4D?VkMPxJdEMIbi zR$=y3?z<=zMb0_>YN*T_I#Pem7%)rn)semGv3lH#&v|T=K$w6@U`rzT-a|~t(y=x~ z;I9S&T{jkFS__-IFBHJkjAI&-K4p!af@nyfj+u8|{&!LUnfcq{g@j7?WrYFRio};| z5RJn^FWAsrwRR9( z75vnCWjj^a-gN{_nC;=zYw~&yS5CGJDx@fe*Y_B?$1eBp?mydRV=EwvwkE`(THOCk z!`0uR9#AKuuG|o7fZ<(ntcF6d>f`7_?&-*{|B#r^vL=N!PailEMEc_z-Zt zOsrkAv`)-4WkfDm%K;V~NlDiqL)>Vbk}|u6C!-Rp8Xg1wI}fS9k0+f0cV?%%g^BuQ zDGwEWCh9@*rV+)T(+dzHH>ORRnYkRj2TKpcXl1V3$YtJ{K7CV=OLA~=axknMPr1M- zL+9%#6&qu7;E4)wIjfQm{V_|{rkyXklyz>o1rc>lFkCw5c{+C+NZEuR0hF1?iM7RV zLfOajmemA{FFu>VV`HDUzmXQIJ`=nPe)hJz%)h=0dG&ki5^rU6c4W6N^h>!0jn>C+ zCECrQe2=1HZ#>fb<*pO&ScI=l!D|O%R)pihBR!B=Ej=h@{=R|fi9HQ(X(MC`|AbAoRj%foxy)~o4T!uU5;=0 zKr0!nRHnQu>dI$a-QJ_1pU7_`X(P|V3hEZ zV+jw6J^eroz0%K-D7Un~zNlWPF>IgFb(Lw|0)rF{X(10}+gHP=kxwoXF*ZIg#@0QgCl!xixZ*T=WT?KT-ZMUqZ&Ytz{OBeL8|{hJ zIEXkav{D68%O9z=o;=%$C>Dz}Cgrm!4a3JR1pbj}8hfqsLt8gbsB4~8rqvfnCfBar zUd2x%Ez!nuy&wvk<3SijR_W@fWB=Y83`bzUa|hVgCC(QqOyiO8(wgYBthB+wY5Fp{ zyryLk8I1de8Zc8?gG%+}{Tvw5Zimb2Cqw0-X=J?Ru$?t8YvaIlH_fM3(`<^NWEoH5 zZ-C8PTqo+;C_@{w?{g1yqj^#t(k-^SFHu;ebPZ!R@Jh@3*_T*QAsHWci1&9Cx_u-F zJ8`+*FGu5|CdI;dX-syNQ2!8R3QMzUURm&Iz2l%3Z%o}?32=v!UdP*S&yVd(pBKaI z)8Eg#BS)dx%13zsF>#Tm1`OgGq5ovH#{onyFkm+$F~G8!qgR9hc3DPT`Z(W2I03S%LTHd z-hu6$89-KUfzy-RHtoWc`317@M_NeHn^oTVmlA7xMB!Q;U57d#;lm#Do3hxcmwyoZ z6OKKS)wNLA-)BW2i@%{5&=cPPd;NIYuib#2EGeImjN3q1b&)?pLynZM4cfexIyNM; zIQor;1DATCfmQP65_K|~_6z;8k$+xsDb3ZasDrhdJ|E?3N5I<0l)_8GK;GLE=1l|r z-&kGmV`h6QWRxAFlL5leM#HI+3cA`#r#^7uHurEe5F2>lW z_;W~UB9=XEEHz}VTV%}RXNfo-d-e7+h{Ienu@+Vr1dAf##~WL&)cSV*p}F* zl%2-xzG3hV(A)Kp0I4dBuO1!$!tVvwNvU1Dz}(oSa-Tvb=`JW-aKkqg(0lct*Ifxj zQ?XCI9eIse#Q(PO%11%NOf~kTZz2pK#QO|;Og@_cnd1o$J>Pb50s%xAUF@-;^Rfq1 zHJeVA^@h|#HEg6K|C`AgZ?)69wWInP3 zIer$j87iNZn{Q}O)%L;M^<7e6!Srg6%Gqsw?7)zL$NIn)CKtb5$UD8A=Xh$ph4bVb0E$K`F=o`5BWR5oM#7Z`!dVspo77aKl&1Ul~a_0y@r$ zY7F7m!S3@#ZimC#p{$k9`}#UD=S!IU>1kT1{958qTHVlLwd}Ozl7{}h(&%p>Tj+Q{+fvZ6 z9d}EIDun9C4v`?9M+wIuD?aX5_SjyJ9d~F$TMti6(aU-hBOuwLWv9#0p&ywKU;Itz&9kfALhm_Fj7!DFq4?1HRtO2Ag})%^oahl{ z)Qxz0Bo$I$6U5d_*%}4swsp-fF@%521G3s4L5h~0tW&@qpmr1f zAqh7UFR0{wLIfJD^~Rdo)w+Q2LMx4q;oXwsc15YOM;|2|rnO1~`fk7={h7e4%TVis z!2Z|jT9zQUhN3ps!c&^@?x!|^wO^CMU4ae5h0zaihST#o!xO9)v@V-(RAPxKQ0H>iF}m8mwsGG3Sx#YYb&*rncv>u7uT46}dkI>keGsrC_Uf5W zNw&29S|5|IEo5$XH7IOrzASXZW(7Kcp2y_**{OXkp9$dvCjX#GI)O3`(CLm5(3Z13D^2uEAWb*28vn`|_gV63#~+Kt5`uj(yJ|+i96w zdIkZ>S)!4*X9usy?%^#g_oY@>;nV)Ly$0AxUp(X^6?na6`;EMrGb@3V73*s-T&QFQ zB560(%iC5^7J<}1t9m=zxcwdOZKVQT03lDUt$R^RQd{`?6UH0$_hGpC*!F1ZsRv7# zkX%Af0^F2pf?TiB#q;m|*_X>sm-IFmEv7Bq`$}DmdeOj2?X40R4)b7*6XlY05X~%5 zyxT0qW-dO0_Ks%Nng=P9#!a|0)DoFO8AN@7(SyGuMWULuVeOH6$OES8ZpeEQ#H8?& zpkmLw=k8+Q^JRKpkgG6;HUm_xS^-l;o0Dv7yOEKl*{}+Yt?glJNd2eyFymBCQbdnb zbdnN8Nc#fhs5A%ZueQLmGg_pWPVVg;`zVRJo(M(-Z8x9Ts$Lv$`VV+WbTR6lp> zh{BCTJS}o|o5qLcCo(!HZ5#=d+TkYaAfI7n^h<1xAMkH$%Ro6NhnqT`c;8Otq? zjAVZClK~=h1$RGzvM(xL?kvscTyD3W{v*(z17tzv3xPg-53neZp+N@1nT^5Lm%r~7 zEKLm3l@aNs1T!t%>D|BfS^uFe`$~ck_!wdPoBE~_f(Lba_Ufm~-5YhgQTb%`+rdYp zh#Nib-Fxr!Kva|W{7FZr@ujlS)ia-*r)Rvi2}|d2l^_K2=WE}x&sI9v<&kfIx&zUv zZmDb(vabT`SfiO*fB{3rcGi9$!DZkki$MA+qd*vcUCk16O6 z8@W#2m)MQav271glsvWnWNdzDWPi{q73RG^U*b)>$LeC9dHHt#T>oPBftCk0(n%6Lrh6>q>X+{>jj~wd6x=&X|DEOP`Rh2Q~V# z;6H?dnG#DCd@5Zfh8=a?m*VeG*LtDZwj3-TyQ!i?wJy3!kdJ=7vG_&0#6or)xI{$+ z(iYzYzun}##l)sPgg39|W&c{&C7#;E$kKE8v@rN$Lm%jh)74731}HwP&*nkB4tTdH ze;GeGq@zp{UR4V8>H3U;%;P#<>kI{(B-c2H(3D8WkYW@zXL%wb?xZiMUK>o!1kUR! zN}W&g@Npij8vmJb>wbdHS0o6V43KAtEbL_5ltm`)NvYzNXgjBgUU?4rSz{e-jLTbX4${Kd@zX+V`LFQ<6sgVCbQa~j{IG|1buQvt5Wr8kL z?vw`UoZK1w%vFS2DU_I6c2`BTk6u-(8ebdaAsE(a zrR(zA69<{T!fT(=&)F28rjmqHvy4JJudE#Db>krp3+*8kRe5m+IJpZkPjTw@1QYEpLkh#g6w? z-v4N%XhA?CDxMGtm?Vg8POvHP^0K4J-#aA86JO&6gDX*Z7w9L;@-DYqzARRS1}3dF zmH?t&$9Mh{bhK;nhZa`DB9Wu7$Bu?Z2|D{6ohL-+9rIr}pqmmq`LbI`S@fATtyBC6 z;S`By6HD&`rRRdkW9=uMg`arjR`#Ho3krKM7sEcYpoeS=ehv^j09CQh1&6Sa z@3kI5t6RL#=28EI6?Htjq@A_PhL00S;gOkRwyq;Gy5xW~l7*N4EswFQa65A%k9_`8 zreRO(NzF5FFsZZ65Xv}5il%Z%Co(VX&CffN>NRZX3>W69=ekaMpKUae3t#?xmszoO z!88z$H#hvx^hK>S7zu{GFUsGUTz!~6Y?}lj$M?UHjT{@-otEaqG0q$0sXf!>TdT7) z`Cg@oYQKYr6pK&g4A5_6DDisF_M~68CEA`YxvPmC@mdW)arh{PF)3jG`h$kNXy&PIaWYAKr60>kr}C(7 zVQQYLrH58dpJdq-+Tt`)uMB;G9oEvS1S`a8al*m+Gw-J?J4anx z?u*qow>G2so^57O%VN!t-09PV#pmiUT%|;vYIu> z{AYoU`J_Useuts-$7%euGyWrCZkc_trmeTZ^=mxRh9}Qio^waoWECA~mDPXKLXKuB zwt;3omXZZs=ucM>v+TaH65m;rE{>Ph$6;mT3$Q#s>C1(_hb))syy73#I)^`~w^n%J zPK6x9kpDa2!jwAT7(=i{F)ZHZD;l%W!Y@$9B17AI`b|JGob4I5t3E%^h+h>0suD0u z9b~DI!#$7d_TWHF9is zHC8*_gxSJ0{wZo`O8cu^6T^0n)E5HNOBMrDg2?hcUt6-^&mt4vGb|27ex(grH? zU2|1mw=dwkdByTB*;Ac28$~T?mqL_ugPjBCw}1?$MplJ7+b~IaxmB!u{qk-tzutbA z0YUm9@;V{YRa&wiyP~Fd%?0DujaIPV*^9B__K#!*C!37&PFZianaYL0C3_KWHV=@k z`#?+EWI66J#9?Pn;isN9yX^iINjz`Q%Cdx>{l}E1uZ0D7wH{&^1+ zT&LWZw)Zon9XlOS&zvK)7#?+m?0O}37QHAEIoX&#k+iw1_o0ZB1BWR;I2fL5qCsk5 zL$ojp>u{AVYO3xW62uQU8XnX`FV~Bv=p>cg?1p5mHHfu-R{g<4QzVYBbndI9-&#l# z4muca8GSGZOg1HG*Z*rISl9}GQWaGG(Md#Z0mziPm2YkRs%I#NN5>Bvo%gkhR5T>HJc82d0qcf2WmG5D3rJAfO9Ur9pDM)LEW=# z`xsB6 z#PH1qZeZm88#nGy zc|SV63(S*JOY0u+N$pqfTmN~Sg#NbEnwG#np?~zSH;1OF($ms9#3OYhg(yv7NouuPQR$g%uNy@DH)T#l|#Hg*bW1}~*d z0Vu)@+e>$lOjkwp((N4n>p*#8l?@1g*4nSq=H0v__Sn^c9BVam<6H@;L<5^de`*bs z1KR;KZWq8%Z+%+qJL9l7P@#YHSN2G-7T-;kRQO8=H2(jGAClb%PDhB;cyl6N;c3!) zR)!aToWRc!UnlF*H{8DI>HS@yL#}7<;!)lEsGntD?uj}rzrDeA4!_z~dl@EG6>piV zsfvd>+!!x6>$4x^#y;;!Ks&33-FPW-FKawA_i@3c(o(JNCMbXYg6X3JIwD}na4-9} zCLuG5K+llKH$05%!8O)xpQjme@UmYc%s8jwb14y6avc$BIq)~SlyUq6;`;$8M41oZ zqU)X*SwgYwdF5uYAZ(W5*{7Emvnqk|JIMo0se!|}s1$sq5J)4lKnw64pLS9B#_{oi z$<@JV;`xt6r?abB=1ZRqYX3WxW&isEz*q5%b4tYo#6pd-g-HliUmT8G{z-hqDt9}0 z3tKsv)nM~2Q0@tnSbSXdcV%;j)+4)GPZdgPa~~wj&@HOT!h5g!EwDLpS0oRqv zNr1_D)F`8?H>t2XFVd`MJyd+t(2)TlV3NLcw4UpiOE&{M*|&TU^YkIGuu(q!(5`gg z$QK(ZPfG`7_Ju=#`XZTgCEbs0X^|8t-G_9#M4w=SsOSeE(M1m9OF;aO z1ih{5Db-8s^)0_!aLN6r{r_VPf9--R8GDoY>bT84g9o4M&r)`rSpMFNFU7~@L4az% z>#F+-<;3r4^qB2bS&u}_zlK2mAF>z%RHW-;3TchX^&+({W4GCWQ9QWBowLfsGlj)` zFEUSU(Vp|&{BsX-6cwEo5Ppqwirw?x+d0Uua+~UGypF3i%td~Btoa-R&j@5j=3c(? zy)6={b{+xU=R}AcVsH615GFBz1`lC{nO zAoSZ8Jj4*VthRBI*hm@5obVew z2|H$HB29y1mHOC-8ijT$kT2qRcXeM+(s(+o_=dOjE1cA1yna9TA$_P+b$Gte9;4me zSyhlYO%e4x-Yfc>pUsA*yB#l6;{L1Bc{5B+zBh%pmwtZv7J6q_FOhw8(`;QC=m zR80Ju#CcrSbWi8mCqp{vsg};d_)@k8s2-T{O9L77#vb z!-!RTUR`w7pN@ZW2lqe;Uuun&ZP=13NhON&HvA~7-pnEm1eR8XZMe07g=hoY*-7Kg z&)+=fN)j-9XMdW3lGfEi?~k3oR-2n|_9(f0Yx1S)5gSLyH7tNLG$qEq?fS?*p+~GcGq+kY@3yTN z=fSF~m;dM@vQ$Oo(d!wxp7&{$nDNgbC|BzEF>ihM&-yN#_g5N}NCCH?j?Pjb9-Oi) zJ@m|&@?PL?`56xqP0`;Vxe4SgJCma1`b~1*aBP*D#EyUGIw%Jyt>CgXg?8W`Ew!d= z6nAoxW2AZIkk9%a(QNKp5J`lUXXybck7Lo?0Y&*oJVzYrk2=H_O9s5@7PE84G?-Fq zbiQCWWWE3fU9)Dh zU{A36TpZ8ES9#>v3|>Fow%6_BKEj`U-#ORML=hq`So}10@t{C*=nF^B z0AE-3MgD6-Z=V|(_?lkKlDx^osE}rOK_!ru3#UK6WkvtK%uSDu7DtD!dFmiNx*BU0OLuct>posV|D^Zl`~z6G-$v z5ZJlQDGiZH9OM)2aFmtE=aGxoqi=5T`=CeRT~i;DSgz*n!q4tPrr|4OqOZq1pBC>W zQJa_?UsCUV35)MGw^-QBoI2P%ig%dkxm*{xCDTF2CJLPV7B25H_S#YSZA^&v&V6!r zf&m!?UY1X~-0a1JU~_=acD-eip6^RzH@2?Hz+Ige?W0mUxxd3#P><~s@FiT2pXy-% zX;wfcL%DuA5byfwM*`Uxj^wc+pDiXO6~`$yzQ9)3vv(vrB9#TXM8Qn-%xPJIK71~%duOMvgA7t;I5 za2pgjGyh65W(f1164dGJo;6C`;Flp77=)vaj`^ zm!5E4LZk|0J3{cM4}5Cusdwwp(|&KX!c^f`8>ccI442(!BG4g&*>Uzdd0a0<*T3HaA$RMt`skF&Zk;ORbK2^&mFkcnFu$3*K{DSq4-c9 zsl%HouBF*Mii`t*m?wK~_UWRh{w0CvKwUIJNH~|XuYw6KSTn!!5*IEdkhd$#A z*D_Ous6XS34oJn9Khi~#;JiWdA7WoF0$gzYCr{PzOw-^XVOItIY=r+b+%FFI+r z?#`iAd&b+kdbD2DcuN~EqU%j8t=TrhmN=GKHp!A;pxr zQZVVcz?s-DnNq_#d>eB6#+_jmdDoHH$`M6J%pyAZf-9Y3;(JJR;j}p(B9NaRhzLo) zdsHzrda(bQQxgae_|Wv+{+`AT;q&#q$AHq+31@FBx~=7=0{qK)cq?l8bk{#n3$W0O zY|RpCn+dGLw(T~}u_%ce4$2s;{X7kj>TCO2Vhc1wVqvbY{3bde!?aT1Tm+v9#xzbv z>No_q6#aK53aI#&q)~y@S~-TiyI&j!wR8p@)yZW#OqX#0kxlYI5q6pH7o7eDCD z1c$a4d|1f)GZzu-jvLD*htqGV&Sav-D$*CetQzAV?@7I90e_8oa(_O#y($j!` z-~RoJ+x6$W6xa!`y`PVyHGYf*p?l;P(R}^ruW3)te2$&>?9J(ib2pscI6nck89S_3 z&T6Jz80MT~=81sstEO$C@fnL%tA%YY`_ORd(^P2#E1<}E?I%c3ezs9wnK-n#$Gnth zbwV4%G~SfEbPq#v&n;W+geVkzd{YprLzE5V>3V+D?-FvVbsMbV*FP*JV|f-uD22UcW)|OeAz(i!SNi zDWRcV9*wioNJ91PJaM$l?^h}>JXeQx*&-izmo6ukUd!WX<7TFZd?RxRzJ*%u?Kv~9 zOA1vVYBS=#dF12RfjyI|<|t$iu0{Qb{--hM%kxfJlIUB|fJbaecr$}vAD3xP8{7>dmdW>-j#rxCy*Rj3uErXn5v7xp|DGkEm zOcLFm9s9ToUJ$YMuTqR=-{lA=C9Q06pi@3aYmqc-9I-ftan6;OAg zNRqqwOY5FRR|th2In>RBZh^61q*02S9L=0EO>ASS{IKKB&>L}!9p^`U*<#1FPfZM0 zo|vd3cy!;cyBdb2oa@rH{fa)!4oNhhAOu90;v8R=PdJdeQ+)O^H1l3B-W{Z~o37JW zJ6o8)-u5fTad2saN6op-Ymvq96IsrS;i<7ldqzJt(Ay5)KWlG)5bdF3-rStVm>$|) zZd9ioo4Bh)RWa7duD9YqLXu5vsT)^A)w7=)MkBmu&nEg@| z)VIoxDXAQWWb#xnxzFkB@K`w@wRHfi0HcetL({F&!~W&EX;pa6?5LN-fBy;>`TCD| z>@PwCpX=xC(OiYfz{i%|1 zBDl*|40f0uE$o7Ic!K2B`JVa-U6lXiXRogSn6i=?>C<=9^1e?snQgKtka%ZIZZnWU`=VUlyowZFw&Xue zY>Jh}eRjMgcB^~yuYxcCkdS0FKkKs>cil`QZw)BAL0I-1LAE4g z7!7g9lc+r@UbTy4<6IRplhRFaKNd&mdAK&eV^PDra_k{Gm>6B|qN*Mr`d%PnlGkD4`(~BRG8lW7~)YU&50uZUN z|AKtE?Ii?&+JnCA0E|A{XwamiJ(_diz9bNh+}Te-Pjf_@2s_=2|zPhPhmw(@@I9yo5-uHR%1-b4G3)~LIf!nWw z?tp!`z@<$`LipF$Xnm?XWRREB>Og;Lc#K2iZn{J^1c&ECc5k~rLn^N5F> zADu*0bb|<@YUnch0`?@vX`3w%1D;ezXyMvc)~80@2{XD*mJ;Cwh?3q1DrNN2wQX(i z8z;Dki}>C|oAI)&&?mYv+h2T0St8GTp$nelZwuEc8&T@tj8I9|9x3v#vADYw4kFVI*O?UqqHW%L+nL5kV_oyyZlTfj% z*&(>n!g|=&Mzld6@ta*`%=r+3DR{In9W8dkW6efF7!;S-I+&uv4e?7$cJF!_P>uHt zlRGK32h04N@1HcPl$B^!d|-bpm>3Yy1ny3t)TManmit64(9Xfsa9?A&@EZK^;duCk$@j>yZtv8hTIun-x^jB5DW zbsyiIT=}coY9RO5;QT{Uj)GRrHg&ZTfpkokZkfXyl?Z;0xEZY#mk_~FEFS)2CjoZe zYsF5VsjGI8Ig0bbBT2ho48i_#r98RN`)JJ6IQX-AYinfIY@-vS+CwTS3qjh z8$%y1q>>5sUarfiIsB!wnt94}_I0<4bD8-F@1S&`--FoK*g$^ZcFKN~PEJe>SM>3m z){6std%iX?_c4M?K5_=0bGtP`#}Eby?2rC z!+jqp$K1u82AW~T(%)znt;sTfZq|$f0=&8lhX02%I{b57L$2t_*5psbP&KDrJm)emr zOS*Ky40uGP6m!&kO${NC#7ii`V$y56HC4OQX&r4O3IXyeSIzkbhB(3O^wSHlC6S`z zEky%;$F|95b1OO7gs})AYDBW*mcL^vMfcIcut^4{kRMCfrp%@2X-L`~<^7h~zOJP0 zqEn_4`UBqlnCRddf&@=0I3?h1C+GpN$h-uO~( zxyU{gIv7zhe^EUD>p|2~hx=5b+k?Zc>97~QLEbZoY3I!ABx@&2M^zj@8lmCiw$*;3 zI8RXmVnvTF;`;h?v13Wy$!TwCizL7Fj!Xf2TgM~qt}lWK4{1WgS09pl4~UuIF`@0H z=N@b*410@N5+eE7fE}r#^|dcUwP7keVoUwI78ZbPwF(?{ui_IlTy)a-Rjm_-h98we zPqSvPfs>XHVhI8KnW;hz8rT)GsFOIjvYun97o0`8#j;#a7sBOCGv2WsR1VK)35;)? zUsOHQhTLcy6H6huxj-73c?Dk6tPA$QDd7{o%+c{3xlb|_%x5HJg3$y7t3||CnOKeW zm^@c}{`DI}*j}HY!52r5Rrqraco7ghmcwu{JjAdiT>V8d8uMIR`PzAZ*&uF(nfymEuK=5c^d^f!b{`5 z<23rHu)dhueZ8%10{Ch!}^+XT#I_2qe=Kyt^nYW zayO_H_X^9uK&qI&KXnBARk%$^o_d$hiB_6X z%lzO~YCLHX(^ZD>W`4K(7JA_DS`*zba+tt8uUK#O>Bx5^Uo|bLk&G3DKR6V2q*#~(nFV0N_Pn&jWjb1Ac9Iu3eqZFN=gdSE!{|Wcl{UN z?|Z-hE_J!kb>_@D`|h*Pe)fKzVcz?kYinS{X7p~Dp{H$arwToJ8W|Ro^3z0hoj{no zwoJn3*pZ;7_N2?9d+N$BMFbCOP)Rv%p8xXf@bmW%633CFVDc~FjLyK)Zo2sU58+#= zv*emw{Fek(Itix0e8JBx2%PWEPRjinm7CfdA3QOW>Bs0_=Pn@b(p_dd%6A4bsfFqb z)zub9oju+KQBtxEPoqLi-1rjM3J^@&O8RIYH z+PKf;^D`eUl&>a=QX4Pih8LXQYbhzS+1Z&Nxka?V^7f4+Jz}Zqe%UuDazOtsqh@T` z9gq(gWBz+==hf*fYWJuPx3 zS)X{6fq&_CT<)IPw>=V#h9;FUFxTz`5+4f~iv4uo+Pu7hv0td`uRGViy07O1Jna5~$5@~F<0hmz%b4E4 z)Ao!kMmK>#;*)?bv$BLo83b89E}XaQ(n2K})I*OkJQoL0W?ixdi~vl_f%{~dZY^@z z%exlGzqXqDFhCbdb-&OimxusC8HC_I7?&K^$xC~N*V}dwH@(G-BXc@lk;#LP;v0nn zZ=4i?*5!h7y1htHZ=T?ui$2)ihpA@1nE+FKDD)U0Z1}ELuxlkrgZuzuB|IHoNw8^S zu5rWSRm*SgS6}w%|0-D*<+8bqH&xx8{D_HhwHywSn3Fb3e*&Ovdd=-zCTU2(!h1Pp za`rWX7OfsTSL5L$n+uYGi-KDW2ZQKW*HusPELR@NHU%!%Mere9amKlW)C)^cU*44C zehAD8aUPwCnZ_#l!;FSj=`BOFAjo;@BlJ!l)wNyVmB18Df-Chu!LSO7x7jhIDA0d! zGh(-)AN3Ol>~mKS*9vnWZ~-9OG@RgWY^ie0+ZNy@cv691$8e1|=x*VuUH14*GARYL zWbf!5yg1^m!S@%EPu|zMqbvWQj$!h^o0++ScylqO{l)r`ouB7lc+iS!&;^GdloWvE zyj<>$!{6+68O|{WU=G!@k_sD9$c|Rmug532sRu249%Ldl!K2r>hLl~Ps*b2hVS@rB}SLK##K!(czTEo zx+T;wf_xYc?$g8La=>mJmEBCI-9&*uJ6PF>s4LRFR&W z|1E8OzsLeo(#ng<^x&ZCWyh5yI#%aeqF>AY_%k&}GBia$pN%;}%~9W*wc?m_<|%b} zI>;cP+T!lVo;7Q}c9eQr@9CxMD}GVS%!G~CB&)Y2+u^kXELJp>IXcwi=}02eZNQVM zx1ob-j|BeKWO3;5A%Kgg%EVS)MA^^#`pn3+k9@7A661s+^fuKH~E10fbgyxpO zWnLQl9rQ+c%;YX>J9z2EBAB>Al(i!mqCp5!x;5dhTwo)QT=JxY3H^!b z{lEIInzo5!BXo zan#lI&`jDf1?vy)+(^87zhZTSu8pBdOH64WwCTv(7+2t$zn?Wv`NsxY&G7z-&?sj7 ze*1vgaMvEZhhazs6E+n)^g(!)cg~B`A(OGJ&iy56I0J zLX670oW9(c-g^DOq4wl<1PA^kvsX%FoDsv~y}w6*IGd<>1>S&D0y2nhII~)0(miUQtS_~+(6(s-?X@=5HMbpoGCO5 zdj78DQFtf;N)%T0v)-BRmk2+~Ja~PqbZy?dI<`mr%$63x_A9Ic)5adxdCj)@iUFXa z_6Od=Q0WZo9H6i_zOx4kEW`Dk|>Wqt;3&*6KkQPDhJw=#*V>Xo=@D8KKy(g zzP4OaQEue9K+Rq37>I||FP=H+Uq^3UjXs-cqM2!mf=0O4oT2Z8i=8Fy71hr8GVJjS z*Y758FHOf8b%ztUZCB$+#rrzq#V~D|%}96jx3lII(kKfBAxb;A?2e@1el7&a`V~5y zCi4rVlL5;)9G=2@eBykaApcaM8`}^?g>B+Ef%rFJb)iV-fZsUpJtuy(0Jkb7F0(0# z#9pgtnI8OCH?*hS# z@IFxUC`JU*U#U(J0#cQcfC9Q8Tyz&^$KO3r zTmbn8V@3UCKdBZp+w}}Nakd3mENPr@=b^c{$Y|-~EwAJ4S&q-p{sr)Usz6&URNI3i z1CUZq98dUOU3{lC@<{u@1YMuGz<}7rx;yYoJlcMqHQMD%Iu0E7OYyGZNt<^lGNh3z z>>0@4h(1V#J-w&(gBb$z`&+|2cq@%t$-efu<$$8yq5W>zyVK073={Pm5SXQHb}gWs z^>K$&cH#VdL-f1lz$jZw;s}PxIOZdj@wm4q?b_DyM$=w@RXMe*fd_vBHBArEm40wr zqXDQbV6R8`{?ftRmgKJ=HxnR)Id8g)t}y%UeA*hx8bWx*ju*NLTB`102<@3o1x22a zMz1eMc}!ZkX@@4e*P2lLZHUmr>oqx%=bKDdCU4=ecya(zw5!?F4wkh`B?by7+#WkR!F#D%Tp+7^$aAi!2b9_5#<-qK;(`?3fo(v)NBep^uwRZl^ z4d~ZD1W7*20ELMl$D~6~COzS5c#+e)UO)D6%GXpnwJ?QVEe8>h{dx^da9Y;Ih0-7s zSZIdLlV~l?8ETU^xy)#-U%F=6RX9J+Eid2?9*h~P(L0N>eG=tdySWiP*W8acNmIpr z`E8pUN>$l>t*z5uTHR`BdJlwNY|p};ojR`BmG^)ZcnAu20(45VV$qN4t(>!F%Mqti z*z4zDTFPf7!bG8(JZO@)=bi*3){&eD``{3Kl}xT`w0L(!nI;r&f@h#bz;6-|oKIr( zk)i}BT<0OLiQ$-s@ob*f+2-mWsq%i)ZiW!NC&w^yrGW^MTBjrjy*H^ zQGA@7$?ebez%AertsTuY>vRR9?xKJnDpdWmHoGXT{$E}Fc8 z_n3hntKtdN1jDLJ>oZMYy~PVLK0<)EwQL>8{1R*SBy_i2LR}_pzYu8Ei6!*W6abM_ zecCO3vHMe(NLbpTJPy)d>tOhgc&w|h{x$3zzsINsJ0+u7lvuPR|6#xF@me{;gV}am zyH@?~+d6MN$)y0PU2mM_-TS`lBgLc1V%}9p8(Gn;#>J9h%wnIK&*v|g@i1WahLsEj zuqQ};I=a2Upf~B@Eh<4%@=MUo?(ox3C4VQA)yJ>vNw+Q=9a?5=g@2qYdvw1>4jEjMtT_uH{MgJ)pK5Z?#DC*ksFGqB z%VfUExmPQZd8#+NLy$OG7T49^6in><^A$*N=-T55H9Llotmcn%QLl8Xkmh+Vbe2V( zCVwnI6gGd;8z(i1Vd+ONxSL;#y!QL#mqH;@o`mD(I#?LrbF3*RkbZG+>@n_nHefoF zg-ZiUGhGrBWfjd=4Vq8>yOKVvCz=P5mDk6Ty)KIa?Uui)mtDwRzAp-&bkLgoTNCo02WjI zGmb)djm178_Es9SZVWcnvWU9U+3{DHdhQ@uI$x#5<4hfh7Pf@#v zoH1=rVM}GzQg!H$dnt)N`pUFH(AuPyN$NF-+IW?sDa0Qa_*LO@^_vbEY=%{!Wtc13 zmmHef`!-GL{}3p-)dW$v4JIbccu^MqUrd&{Jrzz$ocqkdjiy~-TVm5zP(M**R%+9f zjV0A+%~4tS>5n$~B%Um7myqUi{~lgvI`VsaHVS9qu{g%h*q_z1ueE}Qa$x_)d0S5i0;Ae5a0 zJIpV1%wQps)r4phEmTT^on+{TC4e^Jlc!A#oWNZ<;AC2|{E zr{5VIs?{CeTuq=TYR=qwC2RLSZ*j;4ug)6YS%u)DA~YeeO+QAg2mPBzc+acvhY`Cj zSF~GdkKL&!u+)iKa%7W=xY{+oR9+7PX)RDdnOx~i#!$K-l&Sf%CU&iUD65~NmtP*wNnC!nzkK|98Qw!U2ijg0rtNZPlVUujY%QX(LH;(BkxcyU&zhVD zkfyYA7&paAd}b1RB85m+rsaxE)~XtB+GVf1Vz@qAr2`@!ue^E}%w0kSo~$7(f;vzn zWBGC$^+F||PrN1Jf#NOEVrLhUwHw;|&i3pwCZ7?S%`}82S&RgyR=|7FLD`xqtlAN08sKaZ?ShCAoYP51dxfisOBmZG*Ei692qRVj(A>QWa56Mh^}%$1OD8%CmE6V zEPa~z5enCC%J%iqRY2%!1exIN<&qnKEyokPhNSyTFpKLfx#5AM@zi zS2&U=AG&nk9eJn42Vu!3>u!nJ;NY#X-P#3H7hi1iWeVnKGfyN-yxt4%x|NtOt(%Xg zNG06U{Uda8v6@O)L%SV$bx%Hwam9aU8f^OJ>KR!uCyuV&J2+l)mY-DIc?seeFfRR^#1o?SH z#r5?SPcqyIW%l4ThRs9G6S8jg#x*#YIa%KBph?7`F}2(lKp6&iN;m zc2V4L!*49aToVo1P{N1^{$@{L#OlBzB!0bWHM<{aLO6-|6ky5MK?~W|PdU?>4m|KWi zDn6 zYuDG_m!y}qh2#2epQ}Epd*nvv4{Bo`UBNOxNTslEt%K>5Rh4t)6-f<_sTu=Lx4fn` zl`!QsNq0Ygir@fm*0PW0xfqu`10(I0;!u6QF*zO8@jY>Jx`0d{O^4dL5tTyUNflD} zlH&YB#T;+hzh_j^Z^?banM59WpRRlp(bfUM+OBnDUDQ7KYF!OWLEwMEu8Cd5)Pa#f zm1)hrBkiQ0c@h!)r{@_GRQo1Lx_noANnR&87f&P@hxrpax->TqIlo`(Xev;E@~N$0 zQ5B4Zm@FK}|1m7>2^Clc>!9}Xvl0$+Fx+}#dL}5g&7S^h?RAM5inIqY&>=F&lX0QPDBoKdzM{nw6Q~K@J_04wa%Y9^;M}6Oi+OU-;1+< zB^aHr5`NR4L=CKld%k=9bvCFU4x^N{G-z0?ZwxdieLHe^UIp!ue!ub17bELgX?zgd z;>i>P9SlGW9}FrZaK=+MzPsdyAG{i3rJmV#y4O>u<>)=N?W5>)(SBe%k#k1DM2BeJ zmI%@j^*MF|Ymd7xSMt8&k>fIG?VDeL>}xYIb6zFK+PcjTtP)mwLQG%q**@mwS2pF_ zi%Ov4(xNk(2~3cT=W!JLR{G^$+*hB)gQ=B+knTvO$--|uua71o4eJVW3WK27rYb}W zqq|wAsCaZcXyIa<}B5j^CBt}Bw{a` z56_t%El0{?_OX)#EI{!Skwy1|Z5;i*KVDb)30zLty=Qyyrqis2pl*$igMtvaB%G4{ zW%BiJvc0CYmjs=(lJaNjAE}+f4)F56%D(1EWUbJi$2o1Viegjz&o2!!ucNK$ zElGl>#lcy^msfoaRFdJbpJ_i^zDsbqCp@z}J=G9o-ZvXZeb&{Wu&J{?t@x>tX0g=* z-h8;{S+>Q+9NtoGdC}}G(%{{)B~s_M>nY6aZGR3rho>nxPX6Cv-)id;FFhON@l(RS z{F3tGkcqyh_oJ0o#$jE5`jQ#hs!obhJHjayKd&yVGo?(IQ1iv^DZ|Dj9JCl{+0yY@Mz5Mf4uQAfwD)aot}lrhA)%pZhqykP+r(~Fm$Rx(HNUrn$||O9FM{R#?%Tl+UN%vw`qIwHicHGSPcfq|N^NYP-3pGUX&t@oQ<=sez=E{G@ zGz1YDbNb|L=l^PXzXX9pr*l=&)R5p42Xm_6(iK*`SZe9QMejq5CBvOgT_E$G=KB}7 zBpUGXZ-gyce|#MGc#Dq3lDMVpvcra$1H4W^{BI&zLD{j*SD6jJ7!8V}BXg4Righ|ZK^NC;Dyepy7zS`xPe%U=*e;CA@m9u&CW{yqj&H51(!T5H5Xff?Pi^Ok2t+yKt%C1h^UFVBzIV=iH^r%G`fuFQgZ{2kf9x|=?YXe-(v9~V3D1;{ z{Iw);-ly8}_xFbmuzgX(ZFAyfcHs=N9ELSDx+><`6;WW3i2CuSZ%oR8A9kr-ZE!K= zy#5-w6{ccZ8K|7FaDDJ5N^Si9lRS)h`h9 zw&GC12&YLB?obQ!0&7-rJX)jwx@zJBxX4heSKs%boGXHFb#KPt4Y9qh_ME+U0n$*!k}^DcD8Ln=w7Mj5CHn?xIrfA8i%TSxehag^S%QQwrt<3YEYX&| zM|6+G$n32u`DJ~i!PSm?ziy#hXU;`|e8bWExHk0;qG^5{&{^UvW^hQYa*dDGCX~KI z{_4)v1(?w4%d=he%1@2UQ=~a)5OfWoWC`VgsV_Mt)+EH}(F4H0)O%_Dpt9cH)K)nB(@=kop6)b=|xs5Z3#7LjwF z9d5i@^+U!CtdD;0(6#!E(~2U>aOcYG-rWSXmF>?Bh_|%9>f{!~1%{S`Ihv%n3H(+nLTBqPW=|t_^BsJ*7+Ma7 zzr-ec{B8THbBaSQZXqD8u`yP&R8$GpYUY#vkmNlAOHm$=&29zwIz|usg4{&D-=|e# zn~7EhFEno-n@)SJ-Sa7*(Z`E_e<0C`NTi`A2XGfzS=L2gi97(J1}~Nc9L_FD`3|%I zIebO@*<1uSVCwo9f9FBp@RcAyXg)qo6?}Zy#|M}hce6p8(ox)aT446-|EwR%a*!dH z&icSf>X{Ba^h;#%&gm10MhI!b4X5g14!6!`%cHVyk=CDI=gl*EU#=Wqen0lvtrcp$ z<)XAj;j7}qC@y~*a(b%L;DG<_q0uE8Y^%HpD{)?EFR>jhxlK7g_Nwp$JoB!jku-p) zot{3=pXN$@WVdqWlUX}fi}v=sJXwmgA-ojh@?tKG%a0*iO9>eE@PV$S=s{6*_12b8 z@KF&@TUbB>E6a?0-Uxz`1 z9qDSgFMSn)FWX{2@4SXK=^=NE zdTYb}&+rwuaadY}V7FAH{~|?Mp8Nehc9O7nQLATt5d5*s7-=z{v;AiJ$Pt4HCDAJO zjt}i??t7Z{Waw@9A7L4r>{*(^ohP!TP)9WToV1ECmIiHm`$>ZNHO%(NZT*`wDN zjmKMLDdhTp=G|>)7G)qX4HHWsQyUjHR?nigt?N$-{IxRy*mk(gligG_VHAJt6TpA( z7w}FwHG#mgKk~K%Z$26Fe}L@}H_ikZD;xso3vyfVH=TxwX|cav`cv8ev-l`L5smE^ z+@7&BouF@<#SP-OkXVT;zcq|XBO@s>xAhU1yNVTx@Z6xAA`rx&E$S|cX@*spcILfJ zB9YsHCkk-m8}mF@s}7gtG_B>e!>30k{h4=zAmLl+D}sd({>$jEzp7luNJPFR`LwTG zqpXf4=G|KRNt4PYZ*%jmwuP8J=nnTWl?DDSCWOGNpM(uq@Z!aun2=)XeICjdvMdt< zxB3u+NQEbXgZBVJBwKC*U+{oF9Vn)^GR5aHV;2G7UVwb0O;L{=uS-Q8~cqC zOe4!w!Sv>TEnDMGZ)3<~anl=kh}TK1>*ep|OjqhB(5VlCrV9^M^panMh!J3X(?^>6gdehTH@+MU4h2Y zT)epohx>$+eC29Rt~qDkbr56A(C;YbS5>pUWxAPBbjc;(^SiDx!8YZ?w|YJR+F^sm z1EPRkVB-Q#5!U+doo_M&H9 z0+_YV8TFO@0%gaUvHusML`6S#dwRp4N$s8qbWnBr_vd^@3&(&wL-|MXJI7-AHjH`O zE+-QnzUMw<*)~&mu(-#AdADIiAq*f-V7RXhkk06S-e&n{@m}AjF=U_H*66qo*xebz zyi)Mh$Hhm_TmnQ@H!4E=P~>!D`t!jMIF;?y{72Q9!p0i9u7l}@i8&+lUa9O!^cr<;5OeelM zjR+#pyD}uY92T7Rxj}*4&Obdx+)(nf1e(r*!qsRXfCC#4d=$t)M+7u&J{@emu|Jw& zf0zZp$z+Pe^nhT5#Mip_+l`&y>VMTXgu_tW(D~fLS{s^Ws}%HGs2cSD^QjL}yz-V8 zf(|tS_5at%XXmn%iJm2!%afL*r zg$uU<3b=?v_n{y=y9N)l7lA#d6d>26znXBbJ(Z@Eh+-7}f6qN!R6knh`DTUcIDb9g zgEjFnsi6h_h3=Kv04{vV8RBbDwPR#N2c!t_?f~!lr@l~xRnm#o!h5a)+ZlrQxf1)m z(w37|u9jV&1Qz@Vm^qZ=?%xAlKBv`Zw2IKm{Gax%iz!6RNDJYeWCL&)uJBeWxBv2; z`vOS$1GGJab=T$Nz8_nc$r1$;K!Sl;IN(iwVngjymNYzd7E>3_0NRGs^px*v}MuSqC9w+Lfe30cGWOG!6mjfY6 z4O@H^Jwuo?EPtj)yXLEs?+!V*jb!L8iu7U{zuT5p8k zy5`)716!J7!9^nj*a{)P^7jr@yR$)^1oO#n^-`p8AKw}GK%Sv~lLHQa`O1+ ztjAe+C=0fOSU}+jU~@=0G9~980=1V+KlC6KxZjYqhu%a=L;t_PO>sLTa7-wot@1{` z!>{f@o6dI!)Uu07`)$p0_`mI(^QJGyWe7^WlGU`sTn>}Q_s!3?>l&=^>qh)=2yR*z zd+hxE>J~)JBly_#tZ%)Vp8rL(=iZ{gw)w&8AgP)pnxZ}?&KOfEy3=$6UlLB}KZfjj zjJ^E=q(|ogwS#E^*w`-zE8xxalF#_cDZ=tMl@0>EPhoUlaNBhJ;VI4wo{}@#v7h0m za9}4AEXD}%yM_PYd}rQ=OkEUcnAS1Sv3`LsX+{d?Ry&Vif#QCkxlo9Dc>3Sh9v z4VDKtVNkkRQb*RC>0(8)1F%&5F|hBXY<;SRfr4?nGT|!Uk2_rA(&MD(>b&PVKEr>F zylK&wE}KQ}Z-=AGeCcr5jWUmXK-75TOBx7;LEq!zQQ>O9dkx>{_Ox`2j<(&mabFiD zZ#lXU=-M8puii>>p&{m!x9-s7LWxJ+nC`yHR?|00EB=b7HE3pzVY4~QeeN55Ygsx5 zd6NYZmebL4-V2rdT+MQW`!9oHOfd2vMr{w3JD2vf1{;#X54t%=c3-}4%nihtgk`% ztw%rHFOR_dzys9CQjo+$+?v}@1tfG7tD;Q?SHo@mO|TDe4RK`t_xWn^Fs(2xQ610U z$?v3SdW%>30jC~UZr=FD;kOanM;oqTVvJ<*4EYPxZ;8AZm%g^oA9$txOlv94f$N!l zR{6H+AzC)1AAdWqlX#YKcr7M}VqZ*LLF}FYZ>1|5xMFMqBRLLDhr_4LUQ04!f+C!9?O6upnyLhZ`2m)7P z{f*q}ru8T61)%{r0shwBMspP{a}7^m%#Y=^<)-J(4}_OJgXf=ppx!ADd^Q%J0~A{j@|DH&vV6ZP0_+yzqiJoha01Y$~OvwKRw91c%-9P&BiMD z_qpHvTjl=UgzQ@^|MPr8(uagtGu^w#@B00Adj5h#*wddG&(S1Zj18TrwGQddz76LZ z*kW~$lTdg_A(V|D)erqJt?(p*?iQ%(ZSD8_W@x$b1uw_~eiKQi((_5dnawmfO$aG- zwfLDqQ1LXN##=HwLq8o5y{fbXAb8N(TOdL5k%j~}$9oLDJ3}}IL1hA24wyT7B2zLG}-X`K zBVJ=IgfLr&ttWP9ObRIZof+P}dM23^BLQ~wB1SkGTC?(xSht>$qsrW{`v9AwxqU@G zSwu)ZCHCJ~2KxTVWD)B?f+12UE`N9*$!1kbC@yy}{Pmf|Xu@7R_kNEQ4Y;;*+cj&m z@&#zO2?Kv|5!4Gng9&-y^>2tUP-E`-XJP#=p;z5TE@VH8uQCXbu5yX>tc7b31x`ro zdzZZvNAxu7B+e(y3m(AJJckXa)X|Ph)h=aU&OYy7{HnMeNfz3!u<${)O*iQCka|*9I zU1xsw^H#EmPaucMKO(z|5m0&UTJ>u+q?D69IA;Bdl^a4Lo%{=#K zdcjF`<7W8fnC8;(MZ<|FCh65xUBQ;w$|I9tM(+>3qy>#8fwhPd zGe0J8dH|Z%KYqh{Pe8*8R0jqpC>1dUiBjq<62Q+bF!xtA62yr}y1_$^+I4kXjRh>k zt5f#Yg_kz1X2@?~*KrXid-;&o^RaMBY;|p|5t$1mc7Hpg{K3I?2B)Cem#9&Q2C+A1 zDb;^=I*9;D?-#>_TmeRjd0%Wtz7ns~uDQKb>$)M5G5w5xCjM3{iHw#{R{}-n=Eu`L z#+rj7NGsjs>m{;?e3f^)h!Ss$hB~J)NdJ-VK5pTiU>961z3;2H^AitNRuqAMOwW!^ zxI^G8=8Em4(8|11}%QAYmJ3Rg=Q zRpMph=GWP${e7|0zUDS-+Ue+lJU;T|>b^*BPo3ujuiQF`jzqT8gGQVPpV@G7l*SPO zGW#=fev%340`a<%{dCuC^3BR+Ry$dQ(!I4f;%nQ(&XGmvaYaz*5K1nRMKG@Sn52c5 z3qR&J7B9^ze14n?u$dQX+&dpBtUfI0)2|_35(O%KDNgd4klBNE3Yzkhw`7~wl^jq$Y-NH(g7Vt#V>B)= zFMiS-oge94e*+*4CqnpHK84OGBnrq3tzZ55X^A5*pMNgjWmbfFqUU6X1ZA%)V>GRA zT$221@F_&0cKXt&r|`QtkRX7;mUG{_%7Z8r22kke8$L{&)+U!&{JS@>4rDWw*mti2 z*`BWd@vA^LPQ=(Z1Bk-s{6i)rp#->Gm2>Ig^-4^xzL}eJfid0DiO`5s!RZq3OmW|n z<$U_udA(9`ptA0TwWAi7h^kz@lhJTp+}y&dnB?j`-aecbB0Ik+s@D!TUhR_lgoYo180mT!cFsSGg-=#Wy%^Y$!!cTNQf zQM*DZ4}nn<@kQr@s7RszW#%!6lmB%Rj=?XkxW5AbenvDuW)o ze`GQ^{B*>*_hM%m(&{!DpWL+>q92=jq|~A~Z8rVq_vlWf5~r@9mF9mufA>GvrB~ImfA-ox@Cu017rV!FgXXiKmG8+eVKH{E+Or+Cz|c^NK#nS+P) z_Re*=XkS{%{sK`T*Y|?40F@Ge=QC&bhnJi&2s8UU8mw(tjS?MST~+-p24BgkCM!jXZM6sX_Ya_{cN zLtfQ__A3PC5>x}7vNwv-i;Yf^ptTSrMmjn_&%>Gjr`=^jpzt{xv~CyNAyHe^LSiDF-N{j>3J_PvnZ{rv%X zlY<>?*RJE-oZ735@cRCXTfoj@PgzpU!s^R}93WHN{tU$jeN~Q=Y2R-%T!QnD*LvoZ zEW)co6r!NXEVVT&KMjf6W|eI984(i*2tPeOI2f#~1m<6XN7yPv!O+_|KJldkua^`U z24p|VCqi+S<_&NCn*tnbaqZDN46sHqdn2IHiXp$_upQLMn-HR2`_1Do3o6*hGy8XL zvrZycU~QqgOvwLnb)fATS>+5~s1JVIvJhxk2Nbmx&`AUXdqU_t3WFr#Z@``AskzE< z$8@eX$QMpL=LgzCALD?2c;kQ0ZBPZdTla?l4J)`jPnF1`Bhm><@HlYc`z4|bX;XfA$O?~CwtDY$)lPAQori{h|wkD4r zjK`DWLQAoa;4o`2sNFyUcB!edNj*2>o^>BT@#s7EH3%K935a{JLx*LlJ7P-82r}C4C$0-!$IQT#O|JN zn<@%tY=z;c85d+f`*@WBHr}4^)e(!Qca!_##l~*o?m&W*3l5Zcw5w87?pm$_eWT;9 zJ~9pRKgP;RgQY0z3UfGdw&}qS;2?VX=ZC}=A&@Hk_i>olE4~H>^7n)$P*w3C}HugdE#^G!r5z)HNwiHhCNj=r14oM7x*c($qd@=Cs;uY~jqB z6+->^5rb{hdCNFv(E&>g8oUp$_sAw3|@@#~RK7Gqt5`~<#i0N^-<$$>|paGb5 zJPch#TF{!zxS0Ty88%d9O*A)1ikHdl4$S9*+MedHpdN2M3@Aq7^|G+@-eIwL!_FZI zPbFM1QU>T&`OK|IRoV76>@0jgUr)mrbAo3@?UKeob}xB;p;#718_V_WfI{wvDowzx1* zx5t`Y&?(8qk?;k_srl1=Y|_#?&mv7{~een>U`CNuC%Hkd}>mY>i+KUC)OP%|>gOV(Q@fxPWB7T*37^g>AF)p>t|VC7q;x4vH{1GEOm(ejEkULK^Z73UmWuAE4@oUaO?)BMW#1Z8PCESL{{81td~CJv)ztO$c;)=82a|b2 zA^J51M@3yMD2|qA?A!o+^+!UAk)@fpvET#f$sh2}u!k~v2K;j40ZLX%^jRle7&;DR zmidAZDzq`cXT;qfyHAu&B9nabSq;>g{BP5Xa%h7&1DIe^4>QiOs%o}K{vW?lW~Tj(sE!c z=i{kM;6As`c^|@=@9CYNuJUjds&?)Bk!&U*VMhleHB&N4 z9x9ZFbr*;F-A@XV;gV#+;7iZ zhywQ=W!GfRC9sx8bNZMu}P(T_+ha!lGfHVUU>25YcL5UFxN~7w zw?FpZy?fVnopGFT9p~4BtOE_xJ=l2=MU)eT@WY2sz>X|=vNyrv>*dt^m8{D)!3xC` zBlj;Q1gf==m|@JdP6IQ0wU7@QHa~=Y?wy7QtD}Oz;p@OmU7+tf8YaD`z0cxi=vm&6 z$%`i4$UO(SGsv^Ah*~f$f5A)-`CNRyVkSlB&DmQfXcxjnm0gFTW9-d#F zSBozjZulg_;txN9dO!G*b;!{hq9}eO`vx@aRj^1+3Rb!}SQ~XrFg46^KjLxZ;nUyQ z7utn5JR6@7UKD3eaSA?f6P8(@VwM=u@5C9%P2F3)`4Tj`-qH}8b{h~tj?Bs;MIlW= z;o{TDO{vtdR7XXSyKLx1R(M@HGkDAP3Ql-N^G`GGg6owF5ZefqL8W(y+Fpw|{Oqla zu92>R4N#pblELerYNTfbOVA(${o$dsd7)@)din|uX(HeIn&nT2l(EYr+ODUVvp3%8 zTMRj)P+Cy88>NOBSq9Lh^#H}JP5i6(QU#QGM?bP8w45aDqf4Rjp6a1<=^s?5xW_%V zZwiPk)8=)&4SojM2T6uX3psWEj+WSn$<$Fmy|_$2+!ql{&PL6>E_i6d?!EVt=H^ES z2pMsAA7xRUIk8sMuFh?6*5-KA?Ykm2INqB4{Oe90Qjv!_u^yg|3s#3Cc=*(+s2>{| zQcOz^_{;?bF45oEAVF}mFhj=m;nfcy#Dj0&K0J#B7 zRVpTb+M$fz3->W1xR&en;D#8*U)v6f@sM^#eEpIUY!QzDGlw>d@&~PtpiHL*2XseV z8+kHnN0*cq*vlD)_1Dq!;)6#LmaYE1ILAV~r>7Yi?C`aw^T3KJ_@6E_gj`edv+9I) z(7?yy7*6i_ioZ~_=r*EErGl-9rxc!$LB>Zcbtf|)mAjk;s%KWZPF+*_4i3uhQGQ6q zEQh*cE;W9WcBFlZ_u8w>ry8bcNF#;PdkXI7w2;p+r5${sTJ@;0y>&unu?So45O+5QZDyAyJUXWY;G$3_^acPG9LD$zR{p zT7={`%SL+?%l_P6AEfakdj65^$1%9q=2MunQVvbsG4$s8RH_+wFi8nJR_x9G6LG<` z%u$g#ic3{yAWZfKJD-51Ut+TDp{&Lm&pWc8R+K>xJA915q^X8dTqYiIg9NiYIL6o> zBajST-RhPSRgWM8uvq(2M*prW=NAU|%t5XVMt(nDk8Tx9xh3nkxzT{( z^h#`=D4LL4WE2M5jLV*EK{UT;owvH4@g&w=O6aouecZmZL6~5X(er5Xjf3BU&^~l^ zrdOhOvrVgdlO_Pit4Wga)D{GPx~BAx&Y8W)3*inz`ea#;HFlXb*Ota#K7v=nPX(I0 z=XW62mY+PF67AYFiIHHDfz*b-xrg(7EyCg&YnK|QBk4aa7`U#>S6(c z$k;uz)vF#_y*ckQGCPAwDHcQ{vRLAzZSt>@j>*BWq9woS36~$A)!YCzO&3REL zXDeRxp6|*=m8(N$ z;W(#Bx+@OZOXm%GOhQ~uscSk6M?}+xxqWScpV(8uJj6WtTMf>6E?!C&9VpRyKnlK9 zl;o)>4S5SwNnm8-NXR(y*gQL9Fkj(5=0H8RL?R_UnytybA9h*potqls`l!uj?>Dg; zoW>B(dVH6261WWwFY39^NI=|Q?yV31`guwLxx{TgKov&iet z4GpJ1qAwyt|AA-oo66LvlS{@YwhGW{oHI{w>qOiOup0q+CRx6G3BnP)!dcc+_?3kJ zy?OVc)$;XC(8wJxXSgOs3U(fT_HSwTB*1ME3{1(fAFyz{%afm)erYP1+9db=Nz6I1ui5>Oof1*d$WzI#Jzgf23nkqm_z&jo zFBeJZo{fPQhW7|7^YinmkO==*Ut;_r3$Sa-w~x=gd)&<&JEhw;yn`T53_;``f@k1Y zLN$=V-a!&XpWWG)CbD~mnjP|@nQX`Y#$8YyB29ase_*&##tYsY=K)p_kMnO8w#^`f zww*E}Fequ9e6}m3kpBbM2=!x#2eabbaN5%&sMa%!6ksGD;)>IUzD+ zSGo$D*reUp+#RXqHT2es?fs?-VX_RIvZm3)EGW%8O#g;-q@JdE>U8CTeP`f;Y=mre zY-;VgPSTU>Y`Abp{j4iNTvMDV>F$-2Byy%lr_N}Ok_w7FuwC~H<(11s)6SD zd7!CY(2P9fUT$ifcT(y41VrtqQV!f*!*6@?=pG)K>^*q%n>r{Bz=8=m50Dob`Uz26 zUTuuH+~zyi02V2((l+^Z99!^Tp;TgpifJJKg(H*w=xEo`l!oUqkiGNgWeVhX!~Q}_lBRm_M^p3HhnkL2C@`MhBwcKT3@o>R{L^wLE|PfaFguUV_h&^3o0Wej8`#;3DVg9FM{WUMyWE%%o|(-$)&X+Uuc-R z!GQr7PH4PFLwGQ58Q!YOB7}}5zWf96Ky#pz>%b>6?hrk|` zhZsOwX0Zq9n(+g?&vgH-2cJa2{SobI$e2nO;z#Bc<7rDyp*@Efs4&YSRf#%K0F5~5|qfWxVfB6AjcolsptJG|XFV?~R<;pRGqE7s{aJL&n zC49)AxGF7#qGU}7oVczT)I3Ps(7sD+UHN& z`!{;e{4b-5vaUDGx7$M&X3@sJ=*`EhniL%GSUbBc{WB05*C$@g_V{-+ABjS)_6j6$ zNba4>fI_AZlNPRY&w59)vJ{InGB%n@7vFwb@=XgR@i|V-+_-K9N;7&;(p0_55PU&t z`+=e1J*q{uQRA)N5b8mO5t-zJdu>)d+(s0zn9@}2g4r@NKgaPD8$`e6`-(a=+bnKE z3tj|PcJkKywEO%&ru*y3C><76JzLVxT;V%~ESjmKIz%*3V?L(8E`w~aO-Jq=LZN78 zpH*)s3fM>Tcr-7Z=N}gFm%I`xS7%utR7Imx8JFH;=4wF+yDf_MjqBUP*KPm9vlJ}( zAa%cpW_iRaGn!31t46Md7@XamJ(SC!^R#fxh)2+q3j{9UHI6-P({%nlK>-=*fr-r+ z{X5*s+Y;_L4&7q<7i?diQz%{fSe$E8mNPt1eA`I(J6U`Un6puA!)kh(F`_CLXR$|B z4J;VP%zk+#m`xQA{f`W8f{7Cd7L%REr_XJs{zV2((YiQqpi z|KRg8h)2M|Dx+Sx$U%;*lRBpzgA(k0--92^3D79HN!;ZW(Z6rY@F{Xl4xSPm;XAQV zrh-B-L?*4wu{h+dzKWVu#Ky9Z?A>^fYi-C{x}86T;=zwVA=7?=Xor z>SdGj@~kH_)wnu#kGD)`IQj3gBbLY9I+#*U;*-d6XfCnzhyKB@}yVUcPOHP+ZB zBdEY+b@2U*d?kbFX`}K3Xh*1_AsAb8Dni@P;E>=Z)n(A>kaZ=TPE0^7V)&^#Q;CBbU@evYC!M8}h0s2KJ2yZNj{Wm1XU+GV)8vVEp8Q+8a z#m@dCL`&tKv>3!aS3Z1~t?AQ-?)2PYCR$z)(oeA-7b2u4ZVM6XM-CypU9KEG%5PRV zCvZKfTh0BHF6lxR#N%wU43V>uAu`;;fy;alugnnbko)@WVlphMt&>K{<6P{ccGsuc zfTLH{t`v{iw!i*M|J){4)}LTf?s0c{etNqY>A6_^E}%gu_wC>QbX;~Op3O>CNOd9g z%7)YVy%F;S-jBmbbKQ@hxmL7E$ERkI4$O3JjCR0=LEoLXw z_5JA!Z`diS3W*@eLmAyJc^8u!pOMo&;m}re94A-i07&B0%mJY}OB4Bd1YVdF-V7c3=cq76%VuBV~TO4+01d>E-R2T;cY0jH78odi$jpZyD~V zY^a3@Z9?a728VIOE-(o~Js|NHOG_6{{-?prO!Am%JjhHf&kuU-l_Q@lhKIGrG z;U7R;K-V%W@Z!$IF8pe@7E~fNlSOzS&ULTlGP!T+BBzHRuK9i*!*Sd7rT|^H1)2wWc}@Alb(0B>5(%=66iTiAg{7vY zmXxUEqbH~(bTtN||3=7X-0KRBnC(xx>r#B}V3z~vGta==q?Q}eY`{$)k;iG;G{;J| zRR=frUxVZHl9lc#mAFRW9{3<_350vh|NkceoVKv{!Xu8ElbM4Vrj@u&>X4~&0_bIS zZqoJHyU2T5_Zlp<5i+SQRG}&-7PyDUuLi08_~n#(eJ0cbmOiFV!=65jpYnr;5T$A3 zD_m!1EbsWck2Bf+Wf)bwaDgd;6RmLB+6O$J|9mJ2d-KiIVurRFuS66yL)5?;oi??W zSSuS0{kI?Y4MyMf#^wjEa^qq^Hi zp4k2(R%^QIGYfA~7U-gc&~@PK&osr#?TA&`fwr^dxRh2*ApOibONawKn>p-{Yd_^a z@ZWVrMbS7?up?j7XlrVgj41XJKm5fTBry9QoKl%cVi3iPh;K}+H8k=5u?df`J2F1h z9X!aP4;wt?XZ*ut*QL6+f-et_l#6~4VR~MEH-(1DrJLoy-F(-ssl+|NQ~#nEI8Shi zW3@*1mNH&9zgBwke1zTU_(h1=!X;R6ue&F-3DLv3|ML>;rvg_f+4ZtzZ~Uy>z-V<4 zb3j}fz@O|~e9`fF2Pj1SlpcBi&#xy=y57m?9kQ4N4wgEpBWZe1l!-vV|uRE$C9N&e>A`VKg<@knL ziI~i(UWuwv`mZFZscm;Y=+x=dHMwyY?|&F~F-{>P*VFXX3a&GV_l9!Yjwo}6c` zQ&<0QVV0PXI^@C1#b_)?@CU9B3-Sy685h&B+l;RY?r8nqBCeheOZAR&E+DfYowHxy z+i@|!!BLS*YwIp)k0?3~0nXhCfy?(KI zdHfcKgV^A=J)@`8=Vhr@_u!eAay)j@Et4Q7oZ7AJ2Z80)KIjSAWXKwI6-+Ht2jz9; zuf{?5lZP4HhBs6nB>tiKRHG!VOWPzPCEX^zSY#a6JBkkbUpqjNbaQyl#!f#`ZSxZsL9!75*5cgN{}|``^P+>v+V>0~R7)kTKvCj$b|7 zA!R4l^lqcsU<#c-)HUNqEjqCWuCvZI1Bp%!9AcV@f=ZIl>+9`to$rRUe#bSZ-v4bR zs)DQ4wB}PPVOi=*5zV~RD!)bV;IG7MV>>aEJu$c7^5;{PW9){L8Zf^r&!mefExd-_!n&Mk(%(O!{Sc|BuO z)MAu0t+9Id7^1I`C4c2tu>kK_=hZbEwnN({qKqC`@|O~1|~XRQ?RJ@ zYvioylw#(sT}vz6yXjWa=M|zB@&{rqBLOB=t^s79qi-4*c021 zpK?pcr_qrhg&jRPKI=~1XfUxOI}*~aeuaKE@PlVuewppgZ!4^fT?}6xK5``WiKF2I zLAc0ucY&H$5V9RRQZ;j`KbArM2~mdX+3o(atPCX=6?Ql*tnv=@uUSSllmup35xVc zS*5!8`I|e}&qs{u-{wDV%-$v$1i4P*-;vBqeL!Y-fcLx(ouTuA74*j2Q9e07xeqnGCx;{wk^mTxj4C|y{p*XPY!6-) z&eM_#f5#W-xX6FG=d>wAyU8l<>HK(l{cqb1w)xX+ADe*IQzfCIF)MeKC&Z$U*G%#g zgh<9y_Y|TYy)$}edF&5d;tM{;07v?@rP8;wP$*GccW$9p@$jRt^u4KzEl8c9eA0p@ zZTvPqmm=!y{H9V!mwiP%j>6-$GiQ0vif97)+jMaMytsjq`Fvdp-3yV$k#{&bsW8`!Xwsb42c)h1znrp?>U!oc_68SXWuj zoo2nZ#q=#Xov=-W+n7pyd5rzeY;SZKGA5d@ZMZ?zyvkZ_k_9 zXtjmhz}f>Xtr=_NJDj%Y7`*BC=M{?fMTx*h7?{f)48EoOHWY?f|fDDEz%AGq#g6vySZL^i2Q&pS?Cvv9s3naEsfnP4pjd;{2 zkyJT8ivxv7N>7wUUQ?ld)Y7xV+wAnaa|*qU$FMU!RUTdMm5q%lo1h!QiDxkH>W_R; z{O^R{NvYh^V#+-P6yDjru}N!{jt*?Psc6N*yQFBw&}uD3aKEV}`BHTIVS)Tn)?%=} zwI!<-k_Cpj3k{Q}ek)>`o9E(PdCE0H6lID)6H{D6uXiQBIlOc&ja^VM5h1Aj#DgNB zEMH1 z?IEnBvP}Ez$;iw&vR#;MeJ($@xqPyEc%CcLQ&(=ix5V>V3dLk##bcy5dbC$i_zT-8 z%;Edg-o)!@#WeW3`GIDQB<*9FvFl39ZC@?%;lg9?8OsNx8XnHFL7(F(792Iwbop0c zNN?BgQMTTVR1Bs%r&>=kmhn#wmuDZ~faf>T4QMURb z0H6ZJLO|hTW#iH5PZ9YRV5Irnrg{4)TQ(4Ta@ca3<@z$Vq|lB!Cfs#RQNA3&n|kk( zNI=(#DAi{oD}aAQtDU}hF*?o!oGnq6?fOHvcI%Q8wda&{lgv&lq?IC?*<~TDz)Zd$ z_bcopKP%cR--l<0t>&-_cpDhNK9yT|9e!P@sa?-1V{hUx>pFZDyVyFjAqCx!o`KNX zU$R9P=GRLaxrXIrxrS;*z=G#!tY*oe-f66zKjS|Gyw|!e$mGO({^fAjy~N*WdR_Z* zVQkA=AFi9`pX6tCq3yQO!*>Ke7(E!em5Z%P(dOK;Vv+jgiUEpzsbmphT1+88MZHd< zC_&8n_xXJ9@qkYDw)V3%KrCI98x>JZUDt(WHFqLU+) z7X@Dyu-`USz%6NJa{M~$Kdy5M!S6khF%M?JN!gF1%-YP{Ke-;|{9?BCoynC{VjoZwwB9{XD?blZ5O#t^0PHUBpGvoP zK-8SJ(O@41+m=lEBY=1IVMdo=%paY06gRM=YaiseQoDx@S_B9COyhxi0Eq>qw4N5d zH@mYw997C=$TBHFgkNmQ4%~M916jb91JoobZ~ij5-)mW0BmlDlEW>B@wf)5^c$^ktjB-Mq&vB9|x z<+pzP$r>n_a4vAkx}kUWn=+mgSPV3SE-|X1SML7QxhY!VwxA?0jDm$Ic~PrWTzmIm zy&q=aZv}0+MkC5&q1M7m>$k?|6`xqK%k1^3LX*pyW7ozfbt~pQ2b;D~YW#8e#T4I} zI9rRIWf^a7Hvifgf7ihct=X~rZ_sb6lNY_$7fsFad)1+e$%gL?%E@&n&dR4d>ko!p z6I$J>0{adX$jyDT5PDLhK0+Z9HluLrr1Q0U$0|*$P}0Z11+5f?EnGmmJwX_Gl?8hx zy^?sPn;(eZ-se^95B!1Dx^J8D=ErbV%xI;-&LF(Gp(z^Kb|$dhnOrrA7aC<`eyeYL z*o2#2J{!A6I*i*aF(6WxLqz~Q0e#Lww3iU_yg7(^?)fm6{`1azK+k;4R2TF3zyfD7 zdkow_MdZ4$zNsOeglC-s7fG%JpbKC;(W?raKbFXm-&w!q)(wcOGy8C16QcOg+asAv%nb%*atXCH3Bu5MtN?u=1nU^3b4(G=AIl9!{V8NowY{h z%jeUYk+OOOPXG`FEO(KYCX&C33I(|_7A=;n2g!>Z)XLs3qAr1lQ9GcNPU!}IPc#aZ=_!T>-xeurOD@Fq@e3vU>Ammu4F59zjvuJH3$3xA=9qacwwd{F{xEpj z%|pBJ*@}lYY_)&T)V`1Ctj9f-Jcn4d{+=4*{SNBXb|G93 zk32*f8KGMQiD}2L>z{VIf*6QVrYBbZsqN24Yn-t75JGyD?*r<)9Xpp{W zj_git9%PkBVWYZ40n9uma7^}DSfD$OP(tGy2Fx3*`xG8-m(3V-XY2!RL&eb($j)KUW`r8|YZz%!@md~$;B()U``vd_!gaqy_H#%yQYO-es zxo;W#4@5Q~NeS%Czt#euF!&Jk##sdhtkie6iu9j%&Xu=T&%qf)Pa4Sl>SSRn6xS%oV5>;0`bldNE7r7`SoNDO4H zpI0~_e!yiSqsxS0%wnr}JHP%C+_=7ytmAbjtVHNF(*Q&5V9WLU+6uMNs8u$2z^i=A zM@hpfH2li+D=VtqbFbUQ9HOr}Ar9kZ`uNprog!_hArrK=m`=XO=#3*;*E1jP)zgWP z@jr;G&TiZR=Hap{r!$T1Bi{1C5@XwQsPX!)Hc!SGo}IrgxUOms%YYP7 z0GnPyq^S|$Nw-m)XCdmDllIEy7G|PIf)*L%qp}|h+$WERsCka8p)ChE-JSZi+>Ny< zdlF{S-p}5@1|9+G5e1p5S>uldF9G-GFI4I^*&XLJ=3V zbT&I1A2&~ptp`Z6c<^nmC$nF=6#;U+geiAc!pM-;Dfpg@wj%WhJhq%Od^Mz5XI=)4 z?F3U3Y&{+T3UNS0!iI~gqwVx<7$J|vqoTNY6QN#NG-uuawKW>m&($r<($|>!p7=nb z^Vp$%Gl4gXH&a-k%R%+g%+}AiGOnVY+in3PrW92RpeYu~bk)sW;wHb|6~}DDeBFOQ zpMn-t?Ypw~RFvqhu_-?b9W3ppdnZ`zH}3C(VN*=E=iC`=(hfhrk^D3!-v6bj=<)pP z9j{NWMfDq>oZMyxB?}nG=KV|yU3JQ}%Xp}zWFHQT^Jwx0e%&hP-`<$^K4lNg*!Yde zh|3`Q3Dw1Roh{1lG8rh^8nw?J9q-{4e-?(t%FM9~&NUw&dCvdgq%0aNq6vG1tW7#i z&x-q8SQ=Q-9s6))Aczs#wJ2WEh;$=h+L4bvhxVPg=P{a3hlgmU`QvB&f8m32t*W?j zOIenB_+|NHM9oh0`nCkS|AJC<3+5P&g72v&fMSz&}g^j{MMAl<9omk)$Y)SRe!2QOn?*-gxlbkFA+nG)N6t5X(^*m zJ4!X0w+aAzPQsTlhoVfPAb^d6Q0KcKH`%Gjcfxl-{{fl-Q9zr!y?>C>G^p>XqUK2! zt6aI}jB+0IX!8_V;qP}0*^i1&P2L4o0bn0fVIJxuof|qiVzzQDJvzT8l;JC|I{e-c z8uq%Cjv|KVoVlnFFEvKp*XFRtzuUox6Am(l6yGg*$JtaLHy*TzByy8=)G70RrbKIK z4HYpBK>PWen_mem^*n^$6@K<)KMKaCA_TfIzDx!>yHQcaN6{Zxcb_=!eT_)a=lWdl zGqreE8Q+JeoAFQnSy3TwjJf*!Rr`cnoipdqan3Iy&G3QG2> z72KQU!oLIEgJ;Iedq@o&+m_ZAI5e-`?4WWdGvAY533|o)YQ-E(Q1VAaUGCW{X}>IN z##6uZ?oXxVi)-bl&8NcDD~>=WaBN%zRG-S zNkPght9`@wnKRCMcdU)=C-O~AoZ@I>FD*%QgO*ze8BAv za8hlGHW*o!fv*4x!j?`D>anBrv2mOx2^kJzB0!a7Njh+%ZfRThqdd8x7V1puf{!y` zOFlD@wG-i_vGzVvyuKt24ET!&gLWQ(AfRcxA^pzFL%*hhnUu@pBq2Ycw$K7fi?075 zG7Xy|OWNK69ZezirMp@JF85zXdQNzw`GZR8G#yZa^_q0B79PnlOe^E@&iTtlFZm@l z5!r3czRy%+g@`+YnSbl!=sYOnF=`MKi9fTP_ynebuW&B%2oI~hX2P%*Q^QN9Cmr2f z{<_RckZW3We4TQSt1Y$YT}zq5{6arAK8!tjgLo(LBbxXnxAXdg-NX>$oUshKD?)R? z;Kpw<3qrWfvQF(L@lQ`0ny$c`*EL$pZn5mqNRq3ZIiuUBeuir2F_+0to5y9O;p6hH z4H>gYBYgLU7mp|R^A(e0bn&7ua6<+0Rh=-Cfgh4_$>+`W%l|McL|Nebk(p*C?F!1kq6@lST-Fuqso!iJCPM#6KcI~kH)f*44>){Fv zNV9vwF*LSEOm?7mOq z^TqGW9+i?9DM*?5oet3)x{KqIbv>neG)e;#%y`6jY&kL)|q zL2LE4h8AYi^r`!W3Bd}Mv=zEC{-b*5I~zCCxPB!YdAsp+olaCe@~N)fdR%_#&xFPf z4#DlD$1p)?pP{9(8T8%&=^ZRHQU*m_yEn`fML9`DPSBP{G85kXZ9>}OI^&Ii$tnTI zeKvLa2pY?s751*+4D&Ys0RxOP*kVuGP3tX2cP@)d&Fle`g#pu%pq<3W@5?_tPr7Q{ z(KaFiAiBOjqDP<3Nf(*pv1`9@u~eq(<>v8Oi2IN+3-=Q+&l~~hO>u?HDT47PrZwPd z%G5^(9qTW#A*SVf9EW4B8y|IiOoOg=->wQWOcOrrRM=a2o#RNqzqj_ zhLtRD%@aN1MKWc^&@bHir%?dbzsh2=S@hb-pkLtn*{tV2jyMSflg=?afIaw_@2CAq zBJR@y@2mTiZ?mpeM&VW#Ezy>rYoSp@(%!Yme%m9h@$a@a7R zadzuvRPL55pk9vRR-T||7KLm@(eP@gY{d!(#rt;Kv|OkNd``S86yQgpHR2s8SoFi@ zheFDsrdv&+T&d%q2h9|zZbS( zXUEq<7D;)LF_3O7PV9IudiX5Ri)I-kE;Pb0B}(vlqdj@=y=uv-*!MC1Zz9>JbyNPi ziZ4?1kzcz6?8kgig__|T9XKvRa_S|%^5AoeY1K(_wD4}<*O3Lfa%Pq40#fJz z7V8)Mk^;geYz_n!zF@eFJ3fJ*g$090QEGP4W|D|4jZn&@8i>7Mg1QyfeKV*c}h$}FGSB=mAB;tO73K(yR;tk=CKlU{A^Y`7v>%`@E3FV3WZ3Qx87zY*YfsEL(l@k8QDV;4Cw zpZ4GNF8ujc&HZ60to=GF{<{brZ!QH>3u7GbEukhxCo`z+_>XNmV3vE!&9(1U)$1P& z1**3PRE(3`*NU|C)%iqWFXJiW4V{?iU{oqmtxQiaT%nieug*}-#4!1Dz4~SS$*Gx+ zm+$p*Z^gyGpXwdc`O6Nnx$hn6w$IyT`68JZcz?z|J1BlQUTMDQTQIqa!Yw-DF8%@X zW+p-kEWJ4p)8>(b8sO|z+EH{+miW(k=g^JqqYUan!m;}qK|OwVl_lV)q?gxvFmf=> zaan0!xb_cC)9RH`11@gOm?O`rI$;B;i@I*?A)kN(+|m6R9HuM%36{4F^m%Bl904AK zYcSnPUzp;$5mD+HuEA_Sb9)2ozhaqTV4h|dPInP9AHPz!V)mArnZDk!HnVqUKg-$j z4A>zc3E0wBvyJ|dO;mUN-vQ|kz%qhl6OR#2t>oa_95 zkQwxZOsYFTmg2sOK2{Q-ReXeC`?<)@UOavLJ#fay*_3}|zaUCDV054%nRnNT{15Ok zQA+XzvkbuhxqnVkhr5sRW)|7V)<@-(EIAW zsrE>mb8QF>owi&9+#jv<|r>qQ33@b`@+Wu-%y?(r49 z6;>P4e(Y2uK6*@G3;~t0k!>?-)P_5jkc9Z!95`MSus6tNp=pb{xsT z_6U14y@Nd78l%t#^1(r(z|H{}I%(_(AY*_y^>tm_-VNRhz@IJP?axJ|MD9|kf9=`% z4)B;7Bu3gVBm$-8lSlOiciojfk-eAV(eyVy`M40^7ZIt>Xq7-Nt$WYFEaCXi(>r_3 zKNoKZ%ofA7%Iek8J8{gW_W2 zd({N?S)6vTQ0W$a)Jv8(*X=D%dk{)N@-s3&xWBm^@`4?DiIc~@No+T0IE1tk*t{R4 zKyYX%fRAyUTf2Dnmf-!isB1`%gS&u)$fQTR3jcKNM@NSOh594@iXP-&Zu%q*o&iIv z?uC+m$rSnT-3Jy3mZEg;?(mF_e%$_X^(jx_w*6iidM5&yUBMU>{i`cfeskdcr`oq| z9@6pAu&h`0de&_L%`D&J1|^hrV{46kh;aXayVMd_al}vcuiGYBNMIu6z%w`ww9E4# zeyAyB4^txuYP_O2X>$g$a47-zuddZbKk2J z-op9s8X#s9sG$an&R*O1oSn~^IVb!_ z`1>Od#?k}D{L;aOwWF>Xx2lnv{6=bOKbG!S`Pd@zR5I-<(C(I03LA6lBc$h%@{8Lnz?xmR4pBf+!U!uO7d7 zb-n?tGxR&gs6e^&{wkDhGX6tu6-3})q~L3Rk4ULV{xU$Mpp^k&786FXpIjedX~#tY zzTv;gpNShX8SpzClE6}i>3<@2xq_dRv~*1GINW1^Ool3D|3_HA7Qok@8sH3&b@P=t zgP)Ufot8e&;tk9gL@^Ps(e4lKs4*sM|N7l$CHpIV$%3pGoA+Ke_uS)k^gTXG5Vpi3RUz{)GM|00m|IeZ1iQ?kvo1Ycy2f4T znB;evwa$Pgn)raYduaToH9qqfR#c|%fVg(UVfdrn-8fc+>tJntb>&`#seMVp3&=jRi}K?VKNy$Rwa`3=AAzBU?kFf)-spp=7x2H4&xl7iIRV&!YJIb;uEkWoPUC- zgD*kP>ip}A*4}R^EM1)pb@oNDtvZhNof;5#yz;Kp@a}{5T^VIDB_Yz^p!PLdJ89P2>Q}YN}1kx-HRBO4P{R#B$WUE<=>;Qs#cSnV16)tiN zh6A#3lzj} z&H+~olqQt=o$6+1OmEj_oYLoeRpp&!gKZ_IUpfzoe0H0fn*`1Hs=qmPZk#IF^D@{O z9xEAv43FmM?u4!*ZN?sfLbhBz9u9$}6`r;_&G^Z)9Inh4DSm#(fpNmL-n^p5g;8f3 zF75jO5N}21Il}K&D5vJ?+r6VJ+c~rCk z4Hm@Z;luHh*3mV_*0i%Pb9ifl8e zP--egWe+J!i0q6tvP)TGkdo~CZtO(acQV$jW9&0#yMMRu^E|&l<}Y)^%YkWeGn1;Sb5gH97$=p`pIk{qT`h01z0R^pm|&U0MCg>5f_J`D}6xo=bEp7vyl zNogAdyKiaY1>0OPlJ`EPP+Zsy;@#&a3`K~weHorjnYB)ne?R&dU9}KVD!b-vke8C2 zMEx#&)KivTrD6I?M{s>i>A;PlCw)4XA|oLeGBy~$I>M1E`vLC1Bn?`@R zaaN$(N+7_afOKV|oYJU43};y1VK%5lsMtSHUOOxV^84sLIp;#&wC_ZR9mBtw+f*^L z*h;~_Yc8zLUd^Bt(n>bmQ}?l(panUmdcuD$Nvu*>sYo*eNvLlogMrI8SvOSL$n8Wm z;THu`;a@HM;vE(jny8+F!tcX;%(|Pw`URl%#3Tc?KR#SDibf9tqwV&)9AUO}4AjW` z8RbAeC!!6au64P?bYrp{_{2RY*+MI~a_)D{mjq|JvVs`t*Hcj^he-Xul{e{hbfP1>d@GH`zCEVV})w0o|re1o(QXEfqy^V2Mwq z5HBAj*=9=nd!Vq9hhT;GQvr4!v6vyAj`VLKFCURFFnHZaSgqC2>hXM5SI6jYhEY#{ zmf3R6$4cfXtG{lRp|97{-Fw1Hp4C^2!GrZngb>U#Rk`{_@PGOHg_KKE^}w_0z9!d- zUvc&mUw4JscP%UV==bYzm-pR9rOfW0aq^MM?I#2>7cvpSk}{2*6eb&=;-&EE5r2b_ zmo{W&P5fJI2)f|iyLWM1_6IVhAE#C_>feyQXe%<@^IGQT%4{KF4>d)UYmJQ+6Zon=P*Rd@pTa_W?ss$n0oc?r5D8AohCqzwrPcD5)d3j zFKqr94~{?QoEj{@dGo&?ZZkBstqnuT)BZ?m>@LRAKZShO#lmko?`t1>+uxan5VxRJ zU~7H%>>G6Dg126xNEV-`FWkmAkYQN^)2ldW>iW+%k#;{kNSAKe)9L2i)wwOLw|6{v z9!OaQ$UukrLgdvEqYJddOz9X4v1GrZeUEPY!33jBvE_8J3;6pJ-e+6P#qNc=I12CW7XKV35lQP^wNtto+bBc`t&C?*tF;MhWFC!YIK7Oz4?G!{yvZXIFP9tCWHH-n~etcWY{2Tn6(+pc?fL46J-ya8`FG-rTt?*yVY&~?`*iYxg)hK z_F|Z60w_4b;LO9Xz23_^$Kv=u8IUY+s0ItqA04Kk$B!VJEckq1(d}5m? zquf*J^5y)NM4ZA0JZ#};MjJ>ur^tZ%HY`|X620sYo7 zymZ!e@Oyn1ImPn0Z*&kJY@5*>;MLWqdI`qlAtA8Q9H!>hV9y*Wd{=meguHS*icN1y z{1_hk>(H5oZCPp7Bm`;JsN2|bVar~c#jOxU^pR`u{Aq=`r7-}1fcda@P?WhA#3gzY zj6|dl;2w}giL0vY_H?`hi4sR}pHaaA0TLk(91VKFUOF87@AJ-PI0yJ6NKrz zojoGb~12G1U3L>(f}c`5j7INOBlr?(EnCTrMtH zjc;)x@Lby8v`{L%gN1dY8lSF8lAtLK80dqQlp z#U2IKjw;Uv+RFy&C>uZx33(%XGoq$n66uY9h_9yQA$3#`mHY|p!^LLg0gbCcV?5PK z=|^SSsCJq>pU!U*#u-F+R0*JQOmAhupfPu=ffVQOvoV6Sxf$;vR0gc^96m?CqW3+% zxgAS&R(RN5feX8a>LH?r!~9P+&DxZ!Ht?*mQLwM zFC2Qglmh0jqWzK+314RRYX1?F_EEWWeP2iN^!`ii4*w9Zxr&3H&9IxDG@W=rgS86z z^hM1_nW}DkFE*F9!SGOV1BM>w8DASIbaj0Ic_eA~BW-Oa?_c*p;h zL;Fh79|V1hm$xK>Vql6HX<1b~3M2)+KuCDjTV&!TXJkxzG8HbbqY z0@fxPjxfeYX9k)y9z4Ik@WcZLhZQ8;i^%PxYBEoj znujEGjo$V?&trd>Ld8GX5HSg!m7ef}(*R>Xz=E1=%w?U$gq3U31M?7_z`&!UAD{dV z@DWtwA5GoId|@TNwtygqA)fJ<*=@FZArz$W5 zuC5yE{1zhyXIVl#C=zL8(Zz?Z?s3yCK(a=EY5-wo~I!Hl^Kn_EHBgn>1MggagpCEvNtjNG<(_ z;_j7OqhT#xg^5E z(l&Xm)k7N)Lrl|$Ha132l`KS1blzp@T!wK=z z%DLfub|Phf{*d%Pv*#QL0^P)^MrmhQ!)$jv~ z$%l71ti=}$CZQHe>@Q65KY`+9gXJ6>*+YmrMUEfuBznQ@-_pV}+A(P$YqrcWQQPk< ztET~gZu3hBmLuGBodnZle>$V1Jv5>3-nN9L3VAoB7(yr04; z^#)oU{3}UF%ev4A zo&&5`jH9IpJtIk#3!&73rX$U#YiCFubs}V%?EkfpLT>baFMW-1;aB7g2}VV{4_eht zIP)5u5N4M%dCF;egt7da@(0cTXw0Zz1Tfm$dh)>S%o;aVLH7XuE^S!>`gL%2<_O#v zeNG3B3`f7-2_~*~ZD2$PC>i>kVKsC&{-v3#;~MojA1Q3_FR=GB?=8JP74&+^O&HMF z*;l<6nBu4?2Yu^-<=*+W%1T`KeZFGSn%?rDP<`I6oGtFNI>xN&)7H=HZ?ZC%@;+?} zUGFR9`|vAKKniIt(2}R>=a}8^ zc(LS;hS!q(@&(4qJZAj+m0_vA)yZ_Jz3jLzE$LCmK$StCv{}`!_1U=9)fsP#O*^nM zS+IEIu;_@AYHDj%vQKNWja8*J(L&}1!c)p>AM>EpS6daS;jf@as`+mhA7Dh(k^bez zdWSFfdypHvCXp8!{G3^(4}jh2Yz*T`rUP)qKz=3D#u8I(;j!!RtCNVDCM|?b1?jp! zIglEssi@eutS}$2f4cOEw;bjL(A~*ZL4%b6C#gHCOFI;Ag+#A$TYt4CVMAZ|-oFrM zp6$Fg!b*NYUF8to)^8Lwu-u`8>O@@GS!36>*Jkia6z}&n{Hl3B zz%t4ooQ%kTBIYog&aBd-B`k1WgoM%7RV^b*UMmB}>*W-b2 z&5WkiB)os@=*s=pfrDKwpjDcL|7Aileeh-kjHWetp2iEtbKdb)!qoVuS6X3%-mcoL?8reW@_W`hhkxmgUARNNP>C85G_w==#Rno72 zDFqU`B^CBk6pF9M5BS>l(PpG7l#QJoXLt;xx4?ro?g(W8dilNuYy{w7e-;}0i?gM{ zZ-%BDp3jroBN1o(EOrFTIf;_`oKhHe1*aj#;?zbYhwPrD-H*WsmCL#&`{poBscyw^ zD_{iuOphM=V(J=442RN{M!?AdT>#82b>%YT>N=l6-2^_I8{FsY zIaFt1=&=FFs9lux!6M(5+aKsRr+}A7YgxYqQwf^wxpD-*mwUO+ZB*vv*4ow^tExyJ z4}4q{32Ag{Z6CggYGCN;zr6)Kr?c6EC_dwkSB5Ta>ZXeSg;lc}eil5%=aC zG?Nx@hFm=VxO@xxH-EAqjY20(X5yMES)7BqL{ zIhNkSXdpyA>oS9bWPFfc1g-e)j<^eX?9so5Y{hm$cB?74UDaq6Q;i zQgi+Wwp<;aw?mv;T5|0_b3l<$$kr0r5%=6X+EWPNa#~fF^8#DNAItk>G)@LmlUccv z$rr4Q6%)?|a1V;`h-peWC7mPMPA@aO)rYQ11xvb!9Nb8LXM%va%}pr#71_px@V4Sk z8PV&_yP0v!nQo3^Qkh&v0$b_BJ1ZE!8YItL7?6ZmD}%`mFxbM$$cFlqwF;@Xx8uwsHyT?#b&kU(`1T}bjC)xmNV@R)vk?E zyTvMhV~H#76L=KXp!aD;it6GqGq)ByPzjqP??*;5n<0d zWpW5=>fZs`zEkGUuP+UppfqO!ORe#;jhC7S-YIo zZJFD$RNT35@jerjh2&O@Wn$A|0{?)x*A^Bx9v1SHD@K*&#`D zcBvlt85q}@o(zRU*?#Z#sw8Grn$Osw(w=!$$-dza)xMqi-j!yL?STr89E=;L5sXcf zBTV|jt%eIFe`6LCZ8my7?7F* zaKaBWeYHyFG;;ub6FaTgQ%$Mv(=`rYfXZ@fw0y`!{pVyiL}O9}Fn09c$%_HZJZ^*F zNuVhin7{Qi0G_301~@E+d{VUI@>jJ2SpV=JJWX`H;9dO7AI1+5x>gK~2wg*{fs+8p ztfB;vGWF36zQHEXk#SIg&mUo0;Zo1N9rpUATo;)`t;D;1)n7x%>iglvAKnH#?cTpz zH<#W`5o(G1tnqgP4a{LCcUG|1p)Z2lc5Yv#F78NaEo)8u4ZVxGVjS`c&%0>7C$nh% zSy?K0dA$>Jd8tOu(=17mQ(-PqDe12_@G|MfVi`x@>tiA0z_gPh<+NEipwyCEs2~67 zu-mlH^KUaOS*OElE6QDg8~Uof;Fo&oj(gi!m91uVc6-b_vvyI}MilkE+miP%>=3Pm zFPw0edSbo_(!ktnr{_eQO78U@r_79_+><#UJg{Q*2{VtcZcI~=5bm`Io9hi%fPpf> z#YN)oba*@@goeo+bUB8d;9Qi=>A{Lz&|rr*?IzbUcsFu0OaD}bZ=p8mkJQ&c?|1m+ z;X(HA(_ybpgo)AK^@qMKH1IkhY}O2nT1&>J8%RjAXu@!fC{d)TuH_OL>ubfks}(8D zVp#~X!2(OSQEvxk`RYI01r>sHFc|GRfX`vGb$1&XHI5{rU3!sIz#MV*EqzA26n+}j zCc)UKJ9vT1Khd*`N<-y=zfkS`?eM})@5oGv)C1u4kfQga!Sv=t@enutU;Aq9HsNt% z8epRZ7vSjXrM+cW4!4ylMQA6M4+sE|2P=4ZFY2AHXNb0D4wO|^)zHC~SU zT%1Uw?>nkHz$PtyjxZn{{7V_x2NF20sm`Y06F!?fAG)bJm%f}ij8gCuqFp+JWl;tQk}$Rad>C}W z9v$>#AM*=wZ}qy%|47v|!`LrLb_d66^H9)~e-^^_DiyDJsJ(^r11B8t3BKAkhKm(K zm+1w`Zhyt7C`q**zE{lU)i~6>2m6`xW?Gs0)?NMtGVmG11?M)bSPcZbX*z*J&xiFe z;Ze)lUV%qn!Xdj||Bkj5SaV#AzTj7b-yCWTqt6b#oL!|)S#~)l*z|OQ_;>`;K}!>IiJ!HZ$IxF!9gO$Eavd5?QTa@j}Rn^p+Uq?GdYrHHG)cCR6D z>4trd0$rmOLXN!~6r~_Fu2B^JE*1~F0w3~s=qt(IWfBP#? zIv;$(TvYD#{Oaw@r3n$Edr}YK<#e6QBKS^%%!l788t6W-AgpYD z`QO!x&Zi2W^bdx^qASxAFOk6dNW6@G2rrZl>efpm1c%HyYI?^z*tZ=S|6c+gf3oCQ9@=UEzwyxv$X@7nq9zsO;hj#LEj_8i zTPajW{%ts@g;HYNc0`emQsr}QlrVFcz=1=UwLbC}(QTdsch#qEp4KO=Z47cw<$+trP~ zwKD^mO|?VVTh;lHQuu?Zhzj?O2%0YH2L=jVh*23CXrR5O`-A5$A=#J6E+>eW7+ z{Gt5)%53y0+?J0#n8@#Hr2Q`K*5!e{j}rvd@e)-Zi1m%Y@;Z^dE;9KGliof`ky9$K-p6JA31`c4 zHwD0K+ReQ>O{eW0A3!VLKK2WLEN1YqU9NgsT=G@0`!$+0P? zBeucH0|q@FSt$f$A~y~{9TqrflBI#L$MYOSem3OkS}jXMj2=(CYhIH^C4op|_gM(< z+;)a*i2~k$Z6BDiaOrWfu}SjJRhvji5N7xEAB2puJL6eTcYfo$0HW*dHHqP7(^@>Xn0n>0vg{Eb*ZHjt=ight8`fd28ySgP2 zH``pt-o0=nR7_6ZJe-rjB~9ZpmTPAxE-s&Ybtd;iWDl?ooG)bI!g~*Q-)np@aK%%T z00$=?cY2#Kx8Z@`eDmV-AyyG;hj+}-R0m7F>$uzc8y{@qWEEY);~6}!4Zf8tdF7+U@Fxb zggRP=CZHq-kSXC7^ptKmuU^x)0xdRG7n4T8U0^I}vr!8oX7`>B&xTBVO zdT0mK;VV-?xsU*j+^fgi`|PlloPJi7hlbh8mk%ysD$Xl*+N!xU6S#l!XW@Ykpy|lt z81){I3lw$t66Ppznp}a)AR$MllzE@a=hF88RSxYm8>2Kxs%X9X1P;^!S1=y@TFZ;_ zYBDVX6q35jl1qPIb&i5%(NJb<>gN#5K1F?x{Y>%y)7HC+D0*hl*k7~X&DM!iJFvA6 zc`9!qRPY(LC9SX%y@cG+Hu#wCvd(`l2u66pR{5v2r{CW}fsW`|-@3dpE2H+yT%|j% z|8SeSo#|QicU^Mp%YMe@!@1Jon_(ZOH(dEx+ngKfUz&NBUm+Hg3lR0CJVKY_)DO?S z({0Sc{d3MFR=1-x&Y{=6L578=lFv~}w2c{8q#85Uf18NhkhOT1GhbV*{%pp4#vQv% z$5LIF>BHp5EE4Wf+K6WY1T#hq!4g1YXsEzu#2NF5MwP&nsTGv#Xy>`VX$lWbGk1XB zK37Jsy=r0-mK;w_UXBdvSlt13@L4+o7z41AFN>i zy6(xSotm*M2uTr^L527UH#3rz5*Oc*Plvh4`wEAG@<(7evnt}MXwTSn;HBCJtw&R5 zpf;?U;S&zNc3SG|%`cb1Tv}NC&M0Aq zhW;#l*}WFhR!!{t`7@tr!Ho7EuK@t`5^#}H=l!$NI469YjHQ`PC&zNCfc>P-sqe9I z-ShocWyx#Q9tk+LU)|gq6|Osxu~TDzq(40Ui~`6!T-NXKde)O)+IzejxKm=@LVH^% z8_y>>=~rgAz&La2i7LZvlf%Nkw>z#dS@XO9Aj-&YTMaD_hpli_>6$W#5me?;4TJ@{ z9z)?XW-)Xn4b`dn<}FDf&!obt{x$}0adDhfP@+S#dV0k>;x7$grkbNT~ApN^ht%|_gfdu#V&7bwOpc2csKQ^ zyog?x{AYV7bM$Oei2diW@fYy{*p?luKtB+V&D$c z{Z>~fkhiT1O@G5F8frj&uiBi$Gyd2yftL(=Ks1oLDU>L?Ge8OWIL{r%8B3OQh*9$Q z8wmSAntL-XgME?gCZ*6%V1?QwXz5~j`aNA4;~UP{xcYGx{P&bZ&=!#T^XZhROb6aY z&L2v$=bRU24sRL_aeF!;V#S5Py~V$=8`110-B+8Ou?VZM?LO)bA>cNjVx8a63%1_h zocbY}gZurcw+bzBiQ9C?MeAmE<8?<36J*o3^^!owQHh`mwo1nvp0#|{f{k1I7?)#s zABu{bLNCIDGmG0?)-HcSd!%hmb9r*9J$8Yb(3{{%7uYa-wazyU1uUl*4QRg265hw~ zb`+)eEKp!3medywwo9md`k$gjHy~m2wqF;@u(pxR3Lu}~>9|mY3Z8saE!n^2n$rrr z2jC}tB+Q!310u$PHl!tOCH?HlCL}y(!I524IY(w*OJ57WSQToTpn#r#4%kH5R?ubT!TiI{je(*%@<&sr9wUGaB%2wi~Z1 z_nBvo{f>QiQSH}m6xO0VXfZ9COh`efpZbJ2%U{+X)pS=XicI$^O%QRwL5;@`cKK$G z0~O(LuabpKft{nz(5eewd~d?Al9ij9fHLu28d%C-Flu7%n>(#u!H`F^SoOKnv_eKO zM>5W2*vM)=CxprhSYCef`W{HuRQ+#BPb!K--(b@E$rSAj0Gzv+ z58sFjD6*IMAa-i_Z^(w-ZWHdsDg_tV$FWj_Oc8oceYi?5Q?|m%CTa|M#_<*$_FAVG z7Ra_vq`Ny-UCl1Z-4W-z@G89d!HdAvNnV7IpB-*6sXGULWJ|a4 zzP&mJM2J((w}PIOKVJf@$$pW5&|OpdRS?1B^zLo1=haJ$DUNv(_yH${O>UC6>l_Z} zBB)T21U0GZ)Zoj@C9Z8`YR&6}0LQ6vN5~yu&m!uUVFN_;^kb96`s>ydW5LT_Yt6sS z!~2{7S4X~sW!#{MYXF3CG>xG%=NV%T9!EMIy=&ngvhy@slU}om ziaM4WzPG`qzmJ?wCIu5wAHjV(VKCs{6nY0JboWlJPw|Qm z7=28^AIiM}FmaE+nAXG|Wc;_Cw-ovM%R}@Bk-MD(hOCeWtK}cYkc-Uxf=b2>Z;)cw zjBjs|+`gOr8563b)06`4E6#C!?6`Powz?*O#?#YZ9}i$qnEeSjO0x*At@xHtt4E8YhN(Dv zD}O#K=)nH=(4^9mh`{5oU$eCQU3(2BVkGu4K|Cjt)5fJ-X#_*r)OX^CbHD;mh+5U> z)XGTGX$IdZ>EL>Jzy4)jKGR6&2tuPy+K%l`%uxdVP#uH=Zobram+8|YpoiY+fIAa6 z+?_W<$F5}cChJk^y25+JdH><+{KRd^_rS#8NieDM5p| zu6~BRNc=^jp%RJ$1HR@tS!^rgfoRI`Tu^JeRr3|^6klu~^2m7Ci+9ny?k z8KE1CQA<2@EEAB*=pc$FPz-7N!(MO)6v0G2hOjKZSaWE6lT@d1fE#Pirze zZS}#;>4_<2!EKDHn#?q0c_Co*T_y9mTHUe&VdkSI#J|Ow={H}aK0Sw?5>!(;Q5^O0 z76rXb2NJXH^;dg^9y5?jv2=in=;MIIf^+HO<(#iE4DX&1G08s-;3 zp`5H|@>I42C69xd@v9k&R&@Ndsv!;5To0i;Cxax>u#cP{o^CkO=VYy6lLfG=08>ru z$$=m6++L4zHmhiNDh0^9o>c5URCIj%CK_x6l9eQ|ZwnjsKeuDt5vIEY`~ft6gTGK< zUzGMR-s2PRCqqh!n>Q9W)={rbb82FhY4MO@+yGn`U|jV&)Q?Lg8FZXBYDQfZSbU(Ef?YSLmi zHPUaS9B`cSxRUH^FTXAjw~KZvM`eQE9+4DgkF6JPk7~M_Ro9NH<_u6|6Q!{4?fc_X z*8-iUJj%X7N=D`1kN`!R^Uj_E=m}LW<+*d(?g*g=@S%Tj#pJW0a%B>%q8({YK*_F+ zt8U5H7OK5d1dIsEg=T2LY4DMC9R>aZO?u#QfIivKkb*k4DI67$@v;c57v|^dL~M_0_D!WdD~bt|Go8>%4W>50_dC zzs8#U%<5R5e6yi`2_+k(zSt3k@GMv}nPQ5NoupIUT>gXo6*sVh!brHBDCvmes_n=s z-HqDf2U}p5I;Sy_eBR4~0lVLviwX2C)p-w}eVdy;3FyH^(gGK0DVgoC`1YUhKxNYa1K`=?JQxBiv`%DRuIG_^We`^S!e+*jkg z7h_4W#k7=YU~>)#08sarT_`pb=O6`dUwP{o7&ha#{FGq8El9rXAnp9TNWIH~4o=o6 z*zfY)v$zFM#&{$P-Tkf5U*T*?^1(8}Yfbp&?wN-cyz&+wJsgcS=4fx2RZw)^^Eu&> zQ2O5EHycGHS{!bALw4KF%(sIf-ezfE#kmI6gmq=V92jpOI-gOb8Zd24FxS(C7%hfJ zD*W-i;3Z}3WMzv)-)%P!0Z`@l%)s^1lkE?gDbkSM{r675;Z3t;hLyI^M-$U zyl2oGUp{FZnxN)u?9^iW0RNufhkN>`ZHxqEToH!REqOjX$2cU$O ztEDCF`+G-i<|Ho;iyazms5$2S)IYmG!yRjMJN9o4i|{0rxUwk!<@{3O z5mG~<)%ZY54oGHf6r`*+K9}h+wAxknub;mEm*-OIsZ81(LhBFI3yA4RvCl^R@sZCs z=bFd(IxVg;zga$q7qH+HoMR_X-TK{#ZS#m&iPG z*Q>g+LQ3D%EP93z$pI=Jpz_Ev6z^?tA~`4z}Y(xJ3NL<~n+@b5#d&T)Nw% zjMcg;Vx4$kjKJNo)Hw33m;XI60}nU`!KGJbfv4?|1=yT5_q>^11!sFFTwvEc;=PyJ zl<9Fwq4vpa6z)I2F6{Zjebaln!ux6(rErFb*W>ok9x;>J=P%m_L7shnNV9GO zCNx^Gy3l`O!s8Ku{3}HZ;?H%l4-RCfymm0YWKIUu=!$}Bs zcK4eO35;CQJ$^cA)q*?SH$NY=J@ZeB9rJ)~NFHH$f|G;-!}hy?k;f0~4Gzr0xr9D` zpY=JbIT>6vf^9&t=4c$ABeQMS3Gdvn(@0)L2LGPD-{wgcH+g<8E%{?H2Fu|XLiO{% zfrtdq$q+l5q)Bs5?=7we-CF+enwiNY^Y3$K#6kxyx5N%ys*=d6Pp?vooa_A!7)G;wdHqc<)ytR{tgs0VO zTzslD%pZXLz9|j13in$yi@B(kE_HZr{aqwd0_4qDow?xl1qjHc8EcxwamVoj&(34( zI;Y>=U<)7A33Ya0{Z!xsf0m3SH-jE}WErj=a2769zGw3rxQi;?t_u7S!4>=piQfJH zZ86{#8VQvO6lGC}ztIM$4rn`Cfh>b%FW@GhONY7;sKDWVg*GwpoeZdT*Xvm)=65mA zSid?ej{4cHsQ$(&;Ds6LW=DUSuaTDPg}|2VI5ttz%4@}WGqD$syr6l8&eYGm(f}C? z1W!-vp{i6Y_QPt6-iFLihUiR|I1KAAt;l!M^(~p69YbsNL@7cI zvE%qu(Z1sBVke*L4KMD7-X%<@)Fq%w{L@VU<~{#qa!`AN(h9Sx8pMiIAyF@iRK^xE z-#op*0_6V@&0(JBpFi&r{3KQv+JPIb-nIy)5F0AqRT5#fl{9Q0kVwfh^UgNrmX6dt zt-ygWOG|cFHzb zG-FOEotDL&dWqb*4HD{wMn+SCsS)(ai+(WqIuG)buz5IrwE;rQ<$)_5&|woV2Yetj zawNYw6`>fmh?oGD(Ek-(Caf1ADzU_SyTA&l@s4&||LM;y#m|X=2rQs7;&?@6#BMTh zEf#YF0~$YxR&*@>cNS;fP&jELyTB+B)@|6jr%YQ#wjX~JA~8Z43he`<$JL>eZ)aTc zcl4n)=kG55AZDR6?lfJi-II*eTn&q_YxHQ4m)Fp|k~ZlU6J+@4@6wgEA_09X7(+Kw z(C3+-8AC|Tsr%o2|Jg2!_uM%fWZ0U}jScjb<+7|>3pO0Iv_|Q>y^&GNxLT@IVGZ_> zdS&OkSzTQs!(6tD8o$2(jusDW46C;w(rwF zmuB5Gl4AkqT~N_34|erMYceRAzqXq$egX+X3e(!98Dc+kX{+guf<5Dixz_{^&bvSP z+!Y`UIG6p)CxX_40N4CokLfdZ7L}0cl#+dk(!!RXrz0_-Sk^vM)Web)-MQ-%{vgo* zGA((GROqM9b)ujGiM%eRKaq-{f50>mQB4!$9h}pLp+I*rt0+^=OdO!`=R1d9dl}Cz z>Z^G-X+L93gmcEZg-G=&To>=DgyeWMy?@)*9hn8ZCqgx^Fpbv5v4{r5p};mCjVAp5 zb-<-viOK0R_BkOvt;ySX1~;L&46A`A)>*M}5Bp0wKg*ig=v@jSd2?%@c4m`3S`#(4 zr)sa!^?$>CJ5F~i=J(qX=Gv+(&g<)oahN&XAy`c}5hSa8q4coQ*fJV$ujUrk-hEfQ zHTeeJnQD_P5Z`!LTdhy{xwoe+ZGdqWL}ZZI)N_rzE{)$;q)mu&1c&gMt~zHpok|9C zfbA%^=0b1npLO;4djO`A6YkJQlYYeg9}xs|Xfkkmu1#@z9P9_#&27S^HF<9SF?0s( z4rsPgc1qN7!N~RJ0sxiynaYoFV(7TQgzxVJ1l4OPcpdU{`T@S!Gbl05#^(u&3&5uO z7oPMf0og zBR!0Hh&OBJHAy3F)1@-oqk1#26g31M3m5gc=!4cjOJ{GhOt?IPtVfAq!~%DM4F(;K zZ!O#s?sUCXnjk0BTxrx>j1R9DZ^p<5oGw(KDkr2v8~GNlyxP%pmu)?FCb6Alo4F!1{$Wek_&P6c|#Ue zXd&_YT$_gzw@GhOcX|Wi#y|}P13JjDyepsI6(8ATK;XGd_S~P#cOWKOaB%DLt%euWGlFM92LK;SqknFK zv^$HA1AseVLq!WEohuzIb0Y@};9bOD&aCUgETT?;v&>I>@&nZ8Ppk8K6yVenYCr6c ze52gPSIFLnQ4^MwSd4t2jf#NguJvs(I?C>6>DSLL6Nz~K$ZTgIZpItox4`5=GkTyd z@alpcq^-_ltIHu!{`V(j*vI#(k_By>f!3n^Sq8Ws#>d+e^c;UWRd`=nqLx$zuM=kc z=Ua{5^t%iIR{_?mY-g8D$3(2IkMIMVrtSzcqNN36s{K+OeF_R}8ML8^b{u|vi5Q*# z7hBQ?bWzPg*u{`oAH|Fsy-akd4^^b~^(KNL#s=v&1v4&kX2Y&Co2LHkwN{kTmz2S>!WF}6T?)KSoyITHdcnx`bu?M_|6sIgLDFP5BiFM( zPyEv6;ji~clS25Tk2Ds6{Gk>|S(i@-`q0~-vv9zh48}W~AJ7qw=JB%(@!YgzSw77O znV<=6Co(F1XYW6eApCIIpZ#5cNQ99MYgzJ3cXZKb5d0Q*87EiH-#;bFJjh3H9tmrg zL3-?b@C}eT9M3bf!KpkyA`Ga(dBiZ2)Q02c@{k^m2eCE5b$^#!^caF{cMm~kCH!0o zpG$xzvDp^2`@8y4Rb9OP>ZH@Nz$$9t4DQ;jL%nXPZxNaCmpHaL5?~Q!;Nz^)<)VLO zZAj5|e5!4?HilJA{IM@MqMvPDc)jdN2J@dL>In8{EAWrJaRQ_ZJo#LWlUFKguGuc~ z17)o(rOx_13_CGqfQ3+S!P)Mva}$s8XAb{lR8Oys2Vkh>n;4YH#sW5^}T zhE0I`->Eky#=(Pm!APE6Oq{pht&<(h{AOJzP?1(aqHFE60_iT1UBJNW;SXWj_!P-- z7xUeWFh&Z9&EJKW|1L$j3LTmBPi)Bbf1j2hTmLhL{91RUHA5CV|BAT&+}3+bY>OUG+H<=Vs@FNe``f&C0G!s@%mtrq zW)%%+9_%`rF`AFgIm86X<5~w>P+;$SSf;|Oy9=5R=&wFkDeXh4Y^_&o;}VQRUPlrI z>(;V`ovW|YzkRI)jQi6nFf&$@^YEGf<(prhYJ9738Z*9j94E`9pUgOU4WeX**k|@-HXEswE(Y7n|-7VVM+Nb72Ufj1J9QWVO`;Un*DbeGqVDk4R{q~Gu zZTxHPkJi?ZuR{+7)7I0rz#dxVJ@mdJPwDiQ;a~35BJ+?uLmH+( z3{rlFHxxH*LRsidk`N`pjtXsOs3R)mj2D+t`}ZQi&ZM0 z%h3AfZ7^2-u6e;M?V(WSyL6!X&uk+F-i2cDVUu>4mTiGZEh5qZAv=V}Lth4HD1NB8 zfo5T7@zLjQ$+x4;zpb8Y5qJ_vaFPE{Bz|o>7&+bbEJ!Rw!J3kX`zc#3lq~B92I5Sg z`Lq57RK-5jICT%Y%eae51aTN~Dgpihc2->15?t)v-08g!@_WLLHB`*~l>e`*?+l0Q z`=Y)xMh`~s3?h1O(MNO=EeX*@i8hGd86t_^qjx5H7lJ5BL)(7KV6I8JbJ)Ix2iX{42 z)i{lxp?ElFHu$V{!O8uOapm!~G={QBy(a{P-HgGv-;Qq_+K1iSj7cvL-)6B+_`(I` zpBsMOd%rMU)@dgv*-ki3e6%nV)aZE`9DC1=e35C>sfXiS{)cpcZMf;ueB=3d(D$E> zCaO+7H^Flx^>($Ui$zqqbj-ocJk7Fj~|2P0aB^YgN)<2u7J zfh7F?_ayj${7uErVu1*Z)QV|MOgMKeZdw#swKT)&HqSo^Lc~+~@Ax7+h8dMbNroZ-t{>so{S)bNIJoVNWb_DLJ19 zC4gpHwBNui$;aD5ANLbY9pT)c9OTYmI;V5pIg)zuIcSb-I(UyNWPL?*fV%R3W$s`) z_T+ZhAklju{Wx{ifQ5VMy13k)wR_z=HerXrXmBkoVB4*1@VQ+6U(qbL8ty_JIjezt zcddD9g0COodfzg(TTA0o&&el!gzuPp)`Istv||Zjjh%++Z^2OW@IRk1NM+QYOgoevQ2>PR_yPDJDc+ej5t@OYJm(ji1+3oP$DN>e25?Ume8D{3~qVx!-FO zs<1Jrt(@}>qmxt}#LB|;BEGv%?QcmPCuV}czF0l<4#$#K#*=QR3WIoTC@e6{K4uAw z=h$!3Y{?aU;qs?m|3Iv4$o?Qiw4rfmy3L{bXNBxWg^T`6zmG~Jcu1u?MEFM{_-Z>Z z5WkmR7_Rq9ilrXktJo|hrtpjS7RTcD%Gj8LL{%f;nGvr%z{vX+KkO~tFgDz1fwYL; z^1UE`e5p8B+wjYSkwkN07t!7g;iDT${ayVydnn73LPkY* zXm$B8>J9D5f{}QyO{zZ@#*h=oyV3%JYM6n&p^iHhScN>xi0E3%8=BI?&`N$p)%U0- zi7xJyu3*7O1VBW$pS27GuynZ^TXFxJdv78ONNgoOSy*0q@|5b$ zUXMxGMJ&JMiofx&l_H#A2P8bF=y_3Fbw{cUf^oH-9Rg}?!C>x61WvdKN-gkxM29+u zLjl&X$aI7fdWX7CD+*}Q8|-IZ@LcERy}9Y>IdchOD=-Mgg> z08Vi>He(DLClH*zjc8}aUBrcUi!)E22y&DX;ZK3#NDxo3aCS{)^Ai8X z_lxzDaohU6nbn6u({L$?<8KC_T+SmrEf>cH($yjB1zZ?`oW|f;PAKv2qB%f{_G3R` zL2Y(hsFjE7R!8(SgL4pNDP6zM~ka1Fxy z@h{p`9y0-ovxYrUV7l*))BcjraXn%xf7-51<?-B6+vMZ&XG?XYmx90u zkudDXa?flMED4WBZ^*QLZD4h@GxSH%W@B9?4OSzJZKWktO3cdus`Rcz%(g}Qw^b7? zoPg#@GwV5iZwCENGrolo^L$n?woD8CfUvn>cPh|DS%Zqx!i8D-C-^QOti8j7rskq5 z)IHwpTghX^>u`Rb{}9ceI>%>x<2|NUEh&e!Ov@$aT^k z8$|?2rdve&)Y>ICH;vFSXP^CL!Dfb;yIv3hOeoRbWA?>c{N!O|Lq(?ed;KNN?&rQ=rrGoAA+R&| zpaY{$5e`yd6V?9sdr;#)FA9KF!3Y}*K~)*k+xK|uun-HnnnAzyQ5mV}1bw(Jy*i*G zLjWZBJ_+of56`;9HN8n8<$wp6o&&uvK{K5God3w_WhDVecH3%65ToOfZ&o@- zi}~^$w+6ek)}|^~b6GmM(i+s8Il;sD{&dptnn8 z$DVw*rbPG|o-PpnBd&JTIAiX+W04?O((&K2e3skpzgLUNv43M&FJnJ<;n5xZ91(d& zHO>5OXuUrzEiCL~Fbf{FV&{&t|MMiw_e zyM_N3VFMv;d+l7hA@aMhgA}Sj)ij9;WP47WZ^=6*ITCk@5aY=OiDEA-5f7?nLz*J|TUGOWBDx&1~z?vySb~e|s!kUXw$G&HT#G8T!6&1M!?p$C3;@4{f?gVS3<-gE(S=g(Y`_k+2z> zA_1&Jn~BqGfM3C3MI}qJxk_SwjKlGXZD)!r3i>2atsXZ9#bN*`Dd5rZ5E%}2f$)C+ zUN$zgQn4krPK+3_2!BFw)3@BC3WV>YW`)vPHdx&|azx}PvqM4UqsDZ>?o7QD^sP{9 zV7Oxq)dYqYSih5b2ng%@MF}kM2mZ_NaOs|naYibO2bcMa)K&|_HHH?b1aYifJnf&Li zwY`!SvQZI#Pkp)0)aq5eJQV-|1y;}>9oy%;q#GEU6;Dq{s3dJ3Ag}1#Jt21=mIFYX zgP%TFS0PX=Nqv-tbP1aOa91KFf21F^=G%yP_-|nVMV*TW13C%}Pno8{is|i_C;mwy z_Y+@4ss`VMFmLBDAu_u|4c+P6jEm-2bRYBpNK|gYTyP#=dAlQiKs99^*jEAWxfc5pB z9~cQ7c)P`?#QtE1rS3BAHPBnetORaMc#Uwvf_Bpxcw0DX1Ci>$D5cb{KA>hiz&caZ z5z5Tn2Y1ameGG={`SD13{!RAVM=gzg_RK8=!aCzT*#=8H&>N8KxyMSNNU=c*B)~*t z&TdQ9%>on%cGGfp2m1^XE2O1r9u+%&s#rEMAT6<(FS-1U2e0YF97GC7lA$jn{P{N& zZz9@~x6)l6?+E#GOX_M>{FrM!QoH2odhC(PKTm-y%9-2M-uzt8On!f2prkwHMjgJm zT^G}qy}oldkfiUY$@AJ|y5}(vCeJ+y#7k5F(C*Y$p|LgqDy%K4#t1AMi2u|CmihNo zkoMHb-UwDlSv&iy_P>Hzaq~`o%}wxP`e)_45-=Ks|67Bz8D&kNdxv{t|l#*W7mQ{ud7Xp^v*-+ z)%I9!`utwSMGq(bpfb4O(AcVMn`awCHR%J^V9v&&&iWPYi*XV{+O@ddh2nP$jsk5n7552(oP^bf(*J=Zk_X1xTD>`Ll(NwqR-WaYOAFf= zx~4@zMtwb1vg-5W@XWF;fMa(|yeAbp*RQPSzmD!`MPQz+#7U02vJ zUE9W~lePIk3RRSyZD}4G05S9zRlCn~{@8FN8Wqb>{ESiqwyirkF~I}6Kzf1jJ|YGH zYeUtXUjY_s9!_j-S`|&B#%J!{E){geHduRLD2GlmQB4reO;gp`H?B6y>@s(L_EHMu z_%{z16bofyT26BSO39^y4*-{Rycwcle;(!Q@bW{X>_-v8cWty@|A27Mww{|pL(Vfg zly{-xmVn7hctyB9P?vi9ogvi3ODt!~sQ@2vV-C99Yg%a6L%XWqU8sKQymGl+ilP<> zuvfYUy5Z3}jfd%bsOOvpb|;m&&hFDRYuS!P%l&`MFqoo&TIB??-?Bqs;+Ia@=11 zMP(=HTYRp(Y~H2&-D#1>xL1yt*{TFzV2(AH*8VqdjH9OEGWQV-M|=2CA)hACJD`4n z;oTHK0pVX9`0NQpmR3WR4%aAi+l{;YMdtk|0n&sX2zT=%xSk&`#RKm5f2w%Mn+~xB zP`am74_*&6Yv5UVQzI>?iFRM&KX82eI8c@KT44nT{wf$fk>y+G+&)P842U{`wEZwt;yO^4ovk0BWn%YXTg^L4rV$Z6L2*L#y==(e)cG zK_PT{0A;5kf)N+SyIaXYipfn7kmBiTN=K>vkX9=@d*?%|&gSq(oekU}sP8$)E{^N! z5lNS(1m-3od{lc`4Hd|@E(m|e6(0Im!LoK&4>=!9_hRh2)9cFMA3!`dgv$^UHLm;U zo(DD|hQ~HegM>8RSPQga%iwO0B>jZ2)O;a?YrFwMx6^fGIl%GO?U7Yr*l75-sCMze zGo9(@HFe40j(i7fQB#9#*>Of}WO8){U3FYnzrnB-HarW%A;Nmi-rUy@$?dS$1f6dl zt@Lz^G6x;^ajek7WTskfChWHOn&wU!BTny6YS(vAY=Cth1Y-1gO_$!)@=1xUTT!pF zJ;FF~fKRrq0RoGbVDr)4tc9@fn?JH5swonms(6^h<2If!A+-T{Ub;6}dPx^GIFK}I z3PA9l5+{+yR(vcu-_uwK9J7Q3KY%DFKYKc<=4g!_f_U1 z>hn7QZs6$82arG8m_1apF_0rf02rq5Kic`p;K-BNze_@S;F`jp!n@pZ&IC07(4xR| z>i~)r{sHXTdjibR6KmEEyeq60TdKi1U_-02+oCkd>mB4FZ9=ppi& zm_c-cX|_*x37c_978Ve8{wnjuWI=Xxm2%1=IqWL!Qyj?{b&}4i#`= z%raLaYr!|ri7rVZ_#=i)f9B!w)bUaMZ7h{Hfbgt;SSQ*QSiZ63uN+$e!+C!fm@eVc zIV!aq+!0)an6y95kfP;8ME{!qLU_Sx>AW1qM`YeZpWv9Hj?1j(ANLhpyrwzza^|mm zen8|#jJ&d~hT>7%v&F{lzi`7)n`XYi%Df@N-^AuW#FtN!?}a7kMcA%eF1wT833ej- z2pYu^k9Lj#pmyp_8!nI#{WR%}>lYoG94`@OiuSh=g#}KAe#;WzR3-tUXjUOE93; zxvQCjeuZD0IEzyY$>o+}y7EP+6M`7&bV|j^OygkiGFVhb$!dQF1IT{*lWMiPKb38@ zj~@Wxn|gqroYTKzl`FU{+~TZeZlXSMZlUOKWzjik9(I+kU?>_uEbGITHJs&hz04$hHAp( zN=uV#kuos++wY76PC%%;lcvAb%{u2WOFKtqi)c7Fc%(3t`4i}v@OJGZbI?U2P6hE9 z;EEf`thdFNvj9mi2$0+tH{aOSij&S@l~Cxa9m`a}4yQ>*Bw_ZE{d2)g)BoT+p4AMd zT5m6@B>&Qc0sG>`*1mR&DFC_KG#Xxt^YL2Uv+HZ4MCPOgA2*OVYCJNH2#=YUI@PFQ z_Su5fmV=ac)GssM?HDO6@d0`raTs1sO|w!Q__32PA7dS~`>EpzfAF$}_T_`=^eK(% z=3d$pOTKYo5tU^G9pPgDzRR&zyMSU}&k~C0B1(E09bCEe*9Ry3A64V|{nxi~_W+XS z3Mn&7enh{xf|-T*7ADJyDo5)9iP zHNGJ60>cM1A}R@{xB*%xB{OmAn8}ylish1a()-?&mgB^T*%`}u`>jB2u%1pUF*^S3 z?=f62RP5p_HK)h=)vxDuL3vU)l6%E;`hf!WW6MCc)_L%QMRpSemOTIDv+Jvqx6}F; zBg#~G-yLj8ggt(~Wp}4GaPOq*n8Svxj~Z(Np?-#kA*03v=Umc3D|c(r??s2}dhZT* zt=ez@%~ako%QtW8evi}p^uzD7%hhqez=9ue{D>~WY9p^A%5L8v0|%yi6*~)pR}c-y z75DtH$vJ(mf=R*0T*!iPlVZ}#HW2i^;J<;SUmw2iE*q=Frz>B@;HDjx)AbJ+57s#& z!?7@l!%>ziuBI@=Ds&u@5xu~IY5qNtEYK{p6;xQ&y=ZgEU1Nj)gytNxF;k$Bqk-D6ykK%%Nfz@hiS#H_oUn@Ov!JhXvH8Kpocc2QYk$@Gf$k%LP;eibb9bF}T9268J*Ubox1o*^Y=n5)ChHiv;|O6oSkmj95g z5%2Saf46v-u7-`{o}s*99bIPMUuVh7k-r+ zbhYJbCE47X`u^x00K59H%xJR*eyr}`L}u;3!h?n2QM78OB{Qy?SYY_}zwXxGNK_B5 zYYm9=#cQe#NMunHP6LQW7FttI(o_qf=@ZF2MX$&OUDmWQKOt|JW1#R+W`m6LQ71)q2+M9RXVdSyUnFp} zqioSf=PXo{&a`S^U|-8H?K>{if2h7{U(c)Z;W?SwS523EKD}@TZ&G-%3ez^9LH5kIsHn$^;wN2 zTKc3&P7zQOeMy}7C@2{pemd%kW)hIbkReZK3_7VY+we>NuBQJ%?Fz3u3v?>Ijab}M zVmofRcLYJnb$FRa$S*rd!c4Vh^_~pbWIlVV0h$v;SToS{0BfXN3STg^U2-cdiN>_cPM>cuyedp)bgcR1SG}&5IwuQ+nu_{;4bNfgn~jTh zZN!m5!q8?VYAd9fUbQigfbhTTw30vqQ^g47pCPW`vwPE1yrU;)*>{D-+PO>;8H;=L zSg^TnMV_{`tPA&0t|-8%OAZ^JHfy`%R3)MfFq=-jDRj7-`8USXR5)O;-`$9pRvf6B z0)$0Bz_5`(5#bD?tCFJ;O0<@_FrOyuo!(CtKcRH!fe(KQE7->{wrcW8>sRz{qrX!^)t5V%ZJnIB`pB>G*QvU8NpF0DgfS~86=A*KAAYBN+b*8df@r58d zO;b_NfpQN7g@69zg$08{!vs*L`qqw0u{VK}4bmUoptMhj z-G>}rs5=2kHHSknUj#O9q| zV^v6#?)d9YG|s1Imbdd_suLHoc<}At;Q9H0hUw)nnari~TnUZN#%{{*nnW3HR}EF4 zk6xbZ4cCETSG2qIu65?3k00PI$xZ^}oOeoG(sjZu@{%IWX}PhTBrn`Q)Qdjc`GaZB z>HbnD^ zTp>uoBWZ<4_B(U>fsOSr5lmH(J)AUZOqB^ikbvV8|A?dFkr7i=##wj+_%oYb>lm&c zlX6mr+=4@x909$PG?ApJg9m@y6xNI}1fAIE7Y5YMA;+JBj6;t74uiY0RlF%-<{iw5 z+Yy!Zf7T1bZzc08|4}A?rrQ!T5GTg`!d|DQEZaGx%H#FWp0?y^dJbDx>i_^*FnxlD z%=OP1PTcrIRX3wtN!CqdP04YMb!3^29hxH_9CS}Y{YQdT0t9*<12#;KO z&;&~7hiFxw1|+9yS6Ci>T^X2oVO&@BR6TD-u3;-$6)K9|FpCX0x$A0a^q>Y52KCC@ zPW6ZW#cr+Ac{~)SMX%1JITf0~eu7mny4M zGuX@~2^~vQMwf|^(Q?1Q7Dbm*jlh58DE&8`D+f*9GW%Frkc-H=bCrEV&awhOeGAJ= zpcYeAI$Evc7e}<#IPLj9iIjmSeQs=O!ylYo%i>65+XqPTW-!IV)LP_)VIQT%C>C^W z>@*bij`05Xtfzk8YC$RqSV=H=d_qV9Z1#174tXJ>?PssHFEE{OHa#WLU0pC1(<>c6 zeEZ2U0A!+r%WN{2&QXzXs5&XaCfk*wS3ZJC8|XJT?N$Cv_Ft{sHQ|4vIXJdD0eAmd<72{ z!Fb;~2#i4Wk%r6b)?5pXD|-*|snN{*@&@rQ(kDtFJcFWX*ym2Fyc9DYV^sSTw8KmN zH|Jdu{UTEZ$~rDZlD1c-x&9o_EwzqEeXDXlE#v$lCPg?X#f~?LiZlfbi^-SrVW51F zI|BApo#fG5VR;nGf7u?J3?o_fOH826aKc@KmakXLKo~(sPdMeNnQdUhBsoS1a(N-$ znbL%XwC*^bw#{YyeFy*cYAbUddb`%2N)xT;=g7BNBfobNkCT%Q_vA|FNFYK23ILfY zuU~dC6GaUMw8giH>Zv>RJ8D4KE$FkQoCxA|pg-PFG$VK{SbE1$2d*)W*-1ud!sT&4 ztt!>Y6!tt{cU+iQ6$hPV;$=t*swv*_kHL`P0;w3uCuS!go5YunYmYlq}e2(GUZO=C<5AdLtto%r#U4+I`SnZbd^+P1dkCc>j z_ihWa6*cAPQUo4x&aQ^A@VbAFXy$-6rU3WN7TOR9JoESIehsh^jRcR<7Z~{AbF>uz z(BQ4gkJxY@CT!Rox^E)}44_ixLVoJ$-L zW;S#X#5p~8;7+L#86tXRyZduX7IMh`f_}lgk70ebM~CSc52#I< zx6B=1!Ziq!$FN(H3Fg%lyG-;Sq z{`|T*qVerjDZE$UE6detlC~g23=a_YYga*%i|>3j%JA0#Z{{Rt4Cu_m0v})%T$BUC zzXb7#H#cHms}*i$S!f_5#zJ^4vscRZRq=VjYTR4*x@9rjFV-VcgqFlOSSsmV?><-; zqXPQ=;H14GlvHJva0|=|B=sQn_t5AcCDS zlat?l!~`sz==eF-i57KIf$gVTm5b>U*xr-1bhu4d`IlAl2W?jByH+}Jz5Tp3@tucx0Psr|3A=>LNORXZ!HO$5q_ zwLC2V>c7PoDofb>op7i^Bhng zi}eoeW-BhdCq?6-no}G)h-&3IVQqjP;#7}}(-LD%h4Bd%-5K})ZEh#|jUxqtKk$+U z^6&A7BDP!E(@ik{H0+GYU13OT^?cCGy=`EU2~fB1wbQ}Kiy>smI$7LpsK&3ybm=16 zQzD6`ZC?z&wHPT-oFT&bfV$Xsf56aNUguyV>sFl~`&YNmuYzu>rru*CZ#IuR`p={v zdw3*I34+;xL&eZ<~J<%h7y@~ zEU<@)j-yF-%nfhe19lb*rqF5o3LAe~m%s@?!WH zw;78P2zE+O3JBMxvBRTZ!3C(t&!)3DU`LrR8zX*9ygQF&LER`iww_x& zC%hW>X~J&gTzje4N;V)hHz1+0K|7non1>RsdIn_u)H_U47yHBn%hS} zL2iM0WqiT1J%dx$$Sc-5*v`Hze>6U`%obOMj^q#N`PZe2<%?9N&%&{lbmfds0Qe)3 z&06ChTGZk_HxYS4M@$H%CTc>DYLRquZ=kmqBuw1?Ht;#BiL;5nmUNx>G_U8ofq5YI z$5*Gfhal+b^9QBd?+#TNF{QCEeAtK04Y3P~zwVX!&eYPal}!FLBUJJMyupjth_B%C zL1WCtZzgX4SaM^0!Cy@eJ6~9pgQdm(&0%zvK_!%pyhC*BO@#lbhypw45l1hiVEe;G z_YKdstZmkvQZoZxz6%`6r@011PVL#W*SznQ$+vF^WE-rX6ahK9Y{THz3ySvf@8uX6 z!`0Avl*0#D@wKDz11AijB|MHZr|RJdRFjAH*ts@RHq|tQ+t^>c%5JqL2cG5^!vKG% z(TMMuPb{xOtWp-k<~G=;mix&zSD;M{EI)kyi*u1u1*mh5jOC_8{Umw$5r!|Q+^w>E zjt!Rzb4`7rTdTXKQG?d{I2p)MKyQyIzq1i=DiE{w1kHiM>%Uk0ZBrn65eA#!@o zAyJ(A;7$ptzLQlAgcB-_2c`g!*R559Ohhf}BeuNs5SQl?5>mz~d7&xvZK`-v=m{K( zJ{g71IIoFgb1z_2UeWO>BaF+P^3Jq7Uj`9NwBLyOMq#^`$*#R75cCFtvH--w07kzAWwLJt05A zfx702uD-rdSdZw>#e;~bdI3+WDLoG7b&Dtk^?{-w=V~DfMtQ{QHYO4OP^DCAaJ#&9A{?m&Bv6Fr8kK~ z+abi28L;k0dvuCx93&(p9Y;NgXHQOhxa=?%&qR%ltU+QU^AdjXqQYZ;PeCYh^B;tL zIn_@_?hym&kDW9mlSa*)yfgA=;E!zl>|)zoGbDhAQrSo4w6HOtsJj9nZs2WO8;}{v z6Z8s!CC^04D;sE>YbP6Ge;7~8+>CiCzF#T&Ft2dvC&4EEES*T1pJxoc?l`!KZ5nD_ zo!Y43j1RmHY5-r6HP#l6K80==!7W+1j8kbW`pnQy)%a37{2L(QqG2m`OvAgXNDg$s z)lm;K{o+T=oqj1&@~Fjp5&owRXeSTZcTi z&tsqJgJ=M12mliN!+cyn)w(14A_@F7bnNWp^mpV34aGWi z`B~~0(T9y1ju%URWI)Jx8?3O`v8;~5Z2_#dY;FN+9py1Qc`Y1`{~(+7sdQMMS&3%X zb)I^V;b82gfc0vg5O7kGh1)CISdR^Fkv}>pYr4QNDcAQk?+M*6; zi1?2C+kHX6xSP+I-D7u!-L_80G;VO;@b8|TH3 zF^WJ~%-3c^R$36Z*6gE7X{otzlXp_Gon2qOrc=hgNgw{C=cI~%HB@h}sp(?6(}OWz z#qwdZ+_Z-ZuD#II!JK{*0pr6Z z*9XFGUjS+z*#D_#Rg>hnY>qO_@0lAD-DIk9Y_Z@464Tz+cu1hv8};$g9Ilx@EyvVK z>pDhnsFu4q{P_~y({D*k?Dd`SW01$CMQ#&GR9TQg2z2s3{XvdDE{w+*#EJ=7m)!JW z0$Lki(GQZ?GFX?5J!s4&o?`rBY9E=&PrB-EK4}CEef3JITS>MuxO}1EqHK^_{o0CC z0kx&F3Q;A&f+h(h^(m`=dS-lfjj?Dwz09Dqm1+c$oQa&b5C;Fnf(1}{uj4O}XB@FM zrWFoeJWsAr1%EkZd_5auJ#1w~f&@6SPRR4Hrry;Q+pL>-k*}yNrsS=6-j(hL;swEM z$Gq`J3y7bn+^AbIgz!kv-_!Ta8cewv;PalhXp(%Z*mb+zkiWm&mgu;Awt-6^A7oJR z{TH9l>*r_KnANS)mb+Y?=uZ`>45@rqhXcaY=dXb}#0NQrkNFL_HUe!gS!JC`kS11a z1VE|lI0(-((Kk+{e9Ph=E_)4Ph?k?@j>gmo6hELlGSL=b9Zh;sI!R7+6AQ%G#dQm7 zpT3asx?~c1qjK!su5dpPfDL^eG`wq`%Baz|cXkhtR#YX)$CywcWpn8X6}c{r3_3Sa zw@K3ca2=}7$zN$InEGVx`M`I=*OOO_dgrWp-5DouG^4w0r7UcKf~c`SRmNHn8I2AOLlv?${g~i`120UViG{9KgcK+fI4pR zfdmlIt;mO`>NT<=%hJn@S_dk8B9nCAx^f+E_JMf6xSe!vAB={qCiiYH-81RO)_e<@ zbxZT-k&#}%>h2`#Y@I6tAk;kOg4_#wUwJ30`@1Ue0+Lw97;e-7@dVnLe214{lE_~TDRFkQ#|hygYPW>v|NIq&cT0}X>Q zeS%`DhU-Y1-vmE>;luK{6<0p~r05%b+{XL^W;Y@1)w-uL0oc?qA`Wv@=gq`W@ZAX| zH4t#K;&!`Op!$6IR}pat)S|Z-!-sEQo@|KecIdMmOF&p_JP&}PX?2l*y*OA`O3@7g z$gx~A+@R#W2wQ#nZhRI3AU|0h7h_-z7%*~q?zH=VS3jp|9FgxgpFAHqD6WNrzWt}`d8md11zqXr|t+W;gT>QFBHPT32|~) zn-gQj+UB>HL&5xldg-iUeV7#lKvkF#uaMg9T?H(_sKSihyQ245XO5|Ds@Aon09p2* zk^+x7hcZ&%%bwR4pfHSIG=3|e-ttRv{3?O8uK0JcH};RE=fc13E5G%@hXc&kd5`@? z^PE#{Q^rDy*H6J6Y%Tl*5H6I>;pm%#RfPy=!$>&XF zc*0jpkB5Y{mM0VFU+!kj^%#`aYhEw3|q;~Sjk~^J+kOk4*q)M zdMAy={{N3+s%Td|_;xZV&tH4HfFXRR^D%{EW6%qGA!?1&{(k2DlY6f8v)yCdoBiXf z1zHnb3g!Q~M5`nF3=r*!)cn==I|U0bKdAmXyzTs1d{6j|MXKJ}@x?uW`KT*vDOEkO G2>m}Fd3|&M From 2f72e22ff95ee77f4650b609c59d83dd307c938b Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Mon, 21 Oct 2024 13:16:01 +0200 Subject: [PATCH 30/38] Fix CI not running on main --- .github/workflows/ci-chrome-extension.yaml | 2 ++ .github/workflows/ci-front.yaml | 11 ++++++++--- .github/workflows/ci-website.yaml | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-chrome-extension.yaml b/.github/workflows/ci-chrome-extension.yaml index 071104d31cb7..15d99938b130 100644 --- a/.github/workflows/ci-chrome-extension.yaml +++ b/.github/workflows/ci-chrome-extension.yaml @@ -22,6 +22,8 @@ jobs: with: access_token: ${{ github.token }} - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Check for changed files id: changed-files diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index d0a8a4c360ed..20c616e75ab1 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -23,6 +23,8 @@ jobs: access_token: ${{ github.token }} - name: Fetch local actions uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Check for changed files id: changed-files @@ -38,7 +40,7 @@ jobs: run: echo "No relevant changes. Skipping CI." - name: Install dependencies - if: steps.changed-files.outputs.any_changed == 'true' + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Diagnostic disk space issue if: steps.changed-files.outputs.any_changed == 'true' @@ -56,7 +58,6 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' run: npx nx storybook:build twenty-front front-sb-test: - runs-on: ci-8-cores timeout-minutes: 60 needs: front-sb-build @@ -69,6 +70,8 @@ jobs: steps: - name: Fetch local actions uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Check for changed files id: changed-files uses: tj-actions/changed-files@v11 @@ -149,6 +152,8 @@ jobs: steps: - name: Fetch local actions uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Check for changed files id: changed-files uses: tj-actions/changed-files@v11 @@ -242,7 +247,7 @@ jobs: run: echo "No relevant changes. Skipping CI." - name: Install dependencies - if: steps.changed-files.outputs.any_changed == 'true' + if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/yarn-install - name: Front / Restore ${{ matrix.task }} task cache if: steps.changed-files.outputs.any_changed == 'true' diff --git a/.github/workflows/ci-website.yaml b/.github/workflows/ci-website.yaml index ce39d66ca79b..1b015c2a34ed 100644 --- a/.github/workflows/ci-website.yaml +++ b/.github/workflows/ci-website.yaml @@ -24,6 +24,8 @@ jobs: - 5432:5432 steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Check for changed files id: changed-files uses: tj-actions/changed-files@v11 From eaab2d0dd257fb386c79646fd05e206fea252841 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Mon, 21 Oct 2024 13:16:01 +0200 Subject: [PATCH 31/38] Fix CI not running on main --- .github/workflows/ci-front.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index 20c616e75ab1..f42b4d23b334 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -113,7 +113,8 @@ jobs: steps: - name: Fetch local actions uses: actions/checkout@v4 - + with: + fetch-depth: 0 - name: Check for changed files id: changed-files uses: tj-actions/changed-files@v11 From 40152d3b920316eb849d411ee78d1151aff646a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:22:03 +0200 Subject: [PATCH 32/38] 7665 handle the select all case inside the action menu (#7742) Closes #7665 - Handle select all - Handle Filters --------- Co-authored-by: Charles Bochet --- .../components/DeleteRecordsActionEffect.tsx | 110 +++++++++++++----- .../components/ExportRecordsActionEffect.tsx | 31 ++--- .../ManageFavoritesActionEffect.tsx | 25 ++-- ...MultipleRecordsActionMenuEntriesSetter.tsx | 13 ++- .../RecordActionMenuEntriesSetter.tsx | 38 ++++-- .../SingleRecordActionMenuEntriesSetter.tsx | 13 ++- .../action-menu/components/ActionMenu.tsx | 30 +++++ .../action-menu/components/ActionMenuBar.tsx | 10 +- .../components/ActionMenuDropdown.tsx | 2 +- .../components/ActionMenuEffect.tsx | 12 +- .../__stories__/ActionMenuBar.stories.tsx | 9 +- .../__tests__/useExportRecordData.test.ts} | 2 +- .../hooks/useExportRecordData.ts} | 22 ++-- ...ontextStoreNumberOfSelectedRecordsState.ts | 6 + .../contextStoreTargetedRecordIdsState.ts | 6 - .../contextStoreTargetedRecordsRuleState.ts | 26 +++++ .../computeContextStoreFilters.test.ts | 77 ++++++++++++ .../utils/computeContextStoreFilters.ts | 42 +++++++ .../useObjectMetadataItemById.test.ts | 15 +-- .../hooks/useObjectMetadataItemById.ts | 6 +- .../record-board/components/RecordBoard.tsx | 2 +- ....ts => turnFiltersIntoQueryFilter.test.ts} | 18 +-- ...ilter.ts => turnFiltersIntoQueryFilter.ts} | 2 +- .../RecordIndexBoardDataLoaderEffect.tsx | 34 ++---- .../components/RecordIndexContainer.tsx | 31 +++-- ...textStoreNumberOfSelectedRecordsEffect.tsx | 66 +++++++++++ ...tainerContextStoreObjectMetadataEffect.tsx | 31 +++++ .../RecordIndexTableContainerEffect.tsx | 48 +++++--- .../hooks/useLoadRecordIndexBoard.ts | 4 +- .../hooks/useLoadRecordIndexBoardColumn.ts | 4 +- .../hooks/useLoadRecordIndexTable.ts | 4 +- .../components/RecordIndexOptionsDropdown.tsx | 7 +- .../RecordIndexOptionsDropdownContent.tsx | 24 ++-- ...leData.test.tsx => useRecordData.test.tsx} | 62 ++++++---- .../options/hooks/useDeleteTableData.ts | 43 ------- .../{useTableData.ts => useRecordData.ts} | 85 ++++---------- .../components/RecordTableInternalEffect.tsx | 25 +--- .../components/RecordTableWithWrappers.tsx | 5 +- .../hooks/internal/useLeaveTableFocus.ts | 15 +-- .../hooks/internal/useRecordTableStates.ts | 5 + .../hooks/internal/useSetRecordTableData.ts | 17 ++- .../record-table/hooks/useRecordTable.ts | 2 + .../components/RecordTableCellCheckbox.tsx | 11 +- .../RecordTableHeaderCheckboxColumn.tsx | 1 - .../unselectedRowIdsComponentSelector.ts | 23 ++++ .../SignInBackgroundMockContainer.tsx | 10 +- .../views/utils/getQueryVariablesFromView.ts | 4 +- .../pages/object-record/RecordIndexPage.tsx | 4 + .../RecordShowPageContextStoreEffect.tsx | 26 ++++- .../object-record/RecordShowPageEffect.tsx | 15 --- .../testing/jest/JestContextStoreSetter.tsx | 49 ++++++++ ...taAndApolloMocksAndContextStoreWrapper.tsx | 37 ++++++ 52 files changed, 785 insertions(+), 424 deletions(-) create mode 100644 packages/twenty-front/src/modules/action-menu/components/ActionMenu.tsx rename packages/twenty-front/src/modules/{object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts => action-menu/hooks/__tests__/useExportRecordData.test.ts} (99%) rename packages/twenty-front/src/modules/{object-record/record-index/options/hooks/useExportTableData.ts => action-menu/hooks/useExportRecordData.ts} (91%) create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsState.ts delete mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordIdsState.ts create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleState.ts create mode 100644 packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts create mode 100644 packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts rename packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/{turnObjectDropdownFilterIntoQueryFilter.test.ts => turnFiltersIntoQueryFilter.test.ts} (97%) rename packages/twenty-front/src/modules/object-record/record-filter/utils/{turnObjectDropdownFilterIntoQueryFilter.ts => turnFiltersIntoQueryFilter.ts} (99%) create mode 100644 packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx create mode 100644 packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect.tsx rename packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/{useTableData.test.tsx => useRecordData.test.tsx} (86%) delete mode 100644 packages/twenty-front/src/modules/object-record/record-index/options/hooks/useDeleteTableData.ts rename packages/twenty-front/src/modules/object-record/record-index/options/hooks/{useTableData.ts => useRecordData.ts} (71%) create mode 100644 packages/twenty-front/src/modules/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector.ts delete mode 100644 packages/twenty-front/src/pages/object-record/RecordShowPageEffect.tsx create mode 100644 packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx create mode 100644 packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx index 89243ead97c5..dfa609fc0547 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx @@ -1,51 +1,91 @@ import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; -import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; +import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; +import { useFavorites } from '@/favorites/hooks/useFavorites'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { DELETE_MAX_COUNT } from '@/object-record/constants/DeleteMaxCount'; -import { useDeleteTableData } from '@/object-record/record-index/options/hooks/useDeleteTableData'; +import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords'; +import { useFetchAllRecordIds } from '@/object-record/hooks/useFetchAllRecordIds'; +import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { useCallback, useEffect, useState } from 'react'; import { useRecoilValue } from 'recoil'; -import { IconTrash } from 'twenty-ui'; +import { IconTrash, isDefined } from 'twenty-ui'; export const DeleteRecordsActionEffect = ({ position, + objectMetadataItem, }: { position: number; + objectMetadataItem: ObjectMetadataItem; }) => { const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries(); - const contextStoreTargetedRecordIds = useRecoilValue( - contextStoreTargetedRecordIdsState, + const [isDeleteRecordsModalOpen, setIsDeleteRecordsModalOpen] = + useState(false); + + const { resetTableRowSelection } = useRecordTable({ + recordTableId: objectMetadataItem.namePlural, + }); + + const { deleteManyRecords } = useDeleteManyRecords({ + objectNameSingular: objectMetadataItem.nameSingular, + }); + + const { favorites, deleteFavorite } = useFavorites(); + + const contextStoreNumberOfSelectedRecords = useRecoilValue( + contextStoreNumberOfSelectedRecordsState, + ); + + const contextStoreTargetedRecordsRule = useRecoilValue( + contextStoreTargetedRecordsRuleState, ); - const contextStoreCurrentObjectMetadataId = useRecoilValue( - contextStoreCurrentObjectMetadataIdState, + const graphqlFilter = computeContextStoreFilters( + contextStoreTargetedRecordsRule, + objectMetadataItem, ); - const { objectMetadataItem } = useObjectMetadataItemById({ - objectId: contextStoreCurrentObjectMetadataId, + const { fetchAllRecordIds } = useFetchAllRecordIds({ + objectNameSingular: objectMetadataItem.nameSingular, + filter: graphqlFilter, }); - const [isDeleteRecordsModalOpen, setIsDeleteRecordsModalOpen] = - useState(false); + const handleDeleteClick = useCallback(async () => { + const recordIdsToDelete = await fetchAllRecordIds(); - const { deleteTableData } = useDeleteTableData({ - objectNameSingular: objectMetadataItem?.nameSingular ?? '', - recordIndexId: objectMetadataItem?.namePlural ?? '', - }); + resetTableRowSelection(); - const handleDeleteClick = useCallback(() => { - deleteTableData(contextStoreTargetedRecordIds); - }, [deleteTableData, contextStoreTargetedRecordIds]); + for (const recordIdToDelete of recordIdsToDelete) { + const foundFavorite = favorites?.find( + (favorite) => favorite.recordId === recordIdToDelete, + ); - const isRemoteObject = objectMetadataItem?.isRemote ?? false; + if (foundFavorite !== undefined) { + deleteFavorite(foundFavorite.id); + } + } + + await deleteManyRecords(recordIdsToDelete, { + delayInMsBetweenRequests: 50, + }); + }, [ + deleteFavorite, + deleteManyRecords, + favorites, + fetchAllRecordIds, + resetTableRowSelection, + ]); - const numberOfSelectedRecords = contextStoreTargetedRecordIds.length; + const isRemoteObject = objectMetadataItem.isRemote; const canDelete = - !isRemoteObject && numberOfSelectedRecords < DELETE_MAX_COUNT; + !isRemoteObject && + isDefined(contextStoreNumberOfSelectedRecords) && + contextStoreNumberOfSelectedRecords < DELETE_MAX_COUNT && + contextStoreNumberOfSelectedRecords > 0; useEffect(() => { if (canDelete) { @@ -62,17 +102,19 @@ export const DeleteRecordsActionEffect = ({ handleDeleteClick()} deleteButtonText={`Delete ${ - numberOfSelectedRecords > 1 ? 'Records' : 'Record' + contextStoreNumberOfSelectedRecords > 1 ? 'Records' : 'Record' }`} /> ), @@ -80,14 +122,18 @@ export const DeleteRecordsActionEffect = ({ } else { removeActionMenuEntry('delete'); } + + return () => { + removeActionMenuEntry('delete'); + }; }, [ - canDelete, addActionMenuEntry, - removeActionMenuEntry, - isDeleteRecordsModalOpen, - numberOfSelectedRecords, + canDelete, + contextStoreNumberOfSelectedRecords, handleDeleteClick, + isDeleteRecordsModalOpen, position, + removeActionMenuEntry, ]); return null; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ExportRecordsActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ExportRecordsActionEffect.tsx index d7b50ddaf0d3..bd5ce07cf817 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ExportRecordsActionEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ExportRecordsActionEffect.tsx @@ -1,38 +1,27 @@ import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; -import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { displayedExportProgress, - useExportTableData, -} from '@/object-record/record-index/options/hooks/useExportTableData'; + useExportRecordData, +} from '@/action-menu/hooks/useExportRecordData'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + import { useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; import { IconFileExport } from 'twenty-ui'; export const ExportRecordsActionEffect = ({ position, + objectMetadataItem, }: { position: number; + objectMetadataItem: ObjectMetadataItem; }) => { const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries(); - const contextStoreCurrentObjectMetadataId = useRecoilValue( - contextStoreCurrentObjectMetadataIdState, - ); - - const { objectMetadataItem } = useObjectMetadataItemById({ - objectId: contextStoreCurrentObjectMetadataId, - }); - - const baseTableDataParams = { + const { progress, download } = useExportRecordData({ delayMs: 100, - objectNameSingular: objectMetadataItem?.nameSingular ?? '', - recordIndexId: objectMetadataItem?.namePlural ?? '', - }; - - const { progress, download } = useExportTableData({ - ...baseTableDataParams, - filename: `${objectMetadataItem?.nameSingular}.csv`, + objectMetadataItem, + recordIndexId: objectMetadataItem.namePlural, + filename: `${objectMetadataItem.nameSingular}.csv`, }); useEffect(() => { diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ManageFavoritesActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ManageFavoritesActionEffect.tsx index e9767b034203..572bc239395a 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ManageFavoritesActionEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ManageFavoritesActionEffect.tsx @@ -1,8 +1,7 @@ import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; import { useFavorites } from '@/favorites/hooks/useFavorites'; -import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useEffect } from 'react'; import { useRecoilValue } from 'recoil'; @@ -10,30 +9,28 @@ import { IconHeart, IconHeartOff, isDefined } from 'twenty-ui'; export const ManageFavoritesActionEffect = ({ position, + objectMetadataItem, }: { position: number; + objectMetadataItem: ObjectMetadataItem; }) => { const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries(); - const contextStoreTargetedRecordIds = useRecoilValue( - contextStoreTargetedRecordIdsState, - ); - const contextStoreCurrentObjectMetadataId = useRecoilValue( - contextStoreCurrentObjectMetadataIdState, + const contextStoreTargetedRecordsRule = useRecoilValue( + contextStoreTargetedRecordsRuleState, ); const { favorites, createFavorite, deleteFavorite } = useFavorites(); - const selectedRecordId = contextStoreTargetedRecordIds[0]; + const selectedRecordId = + contextStoreTargetedRecordsRule.mode === 'selection' + ? contextStoreTargetedRecordsRule.selectedRecordIds[0] + : undefined; const selectedRecord = useRecoilValue( - recordStoreFamilyState(selectedRecordId), + recordStoreFamilyState(selectedRecordId ?? ''), ); - const { objectMetadataItem } = useObjectMetadataItemById({ - objectId: contextStoreCurrentObjectMetadataId, - }); - const foundFavorite = favorites?.find( (favorite) => favorite.recordId === selectedRecordId, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter.tsx index 69bfd3305094..ad47a1ee179f 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter.tsx @@ -1,13 +1,22 @@ import { DeleteRecordsActionEffect } from '@/action-menu/actions/record-actions/components/DeleteRecordsActionEffect'; import { ExportRecordsActionEffect } from '@/action-menu/actions/record-actions/components/ExportRecordsActionEffect'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; const actionEffects = [ExportRecordsActionEffect, DeleteRecordsActionEffect]; -export const MultipleRecordsActionMenuEntriesSetter = () => { +export const MultipleRecordsActionMenuEntriesSetter = ({ + objectMetadataItem, +}: { + objectMetadataItem: ObjectMetadataItem; +}) => { return ( <> {actionEffects.map((ActionEffect, index) => ( - + ))} ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx index 75267e445d49..acf4a9bed732 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx @@ -1,20 +1,44 @@ import { MultipleRecordsActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter'; import { SingleRecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter'; -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; +import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; +import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; +import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { useRecoilValue } from 'recoil'; export const RecordActionMenuEntriesSetter = () => { - const contextStoreTargetedRecordIds = useRecoilValue( - contextStoreTargetedRecordIdsState, + const contextStoreNumberOfSelectedRecords = useRecoilValue( + contextStoreNumberOfSelectedRecordsState, ); - if (contextStoreTargetedRecordIds.length === 0) { + const contextStoreCurrentObjectMetadataId = useRecoilValue( + contextStoreCurrentObjectMetadataIdState, + ); + + const { objectMetadataItem } = useObjectMetadataItemById({ + objectId: contextStoreCurrentObjectMetadataId ?? '', + }); + + if (!objectMetadataItem) { + throw new Error( + `Object metadata item not found for id ${contextStoreCurrentObjectMetadataId}`, + ); + } + + if (!contextStoreNumberOfSelectedRecords) { return null; } - if (contextStoreTargetedRecordIds.length === 1) { - return ; + if (contextStoreNumberOfSelectedRecords === 1) { + return ( + + ); } - return ; + return ( + + ); }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter.tsx index 4b61fa58eadb..9c4b1d528f21 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter.tsx @@ -1,8 +1,13 @@ import { DeleteRecordsActionEffect } from '@/action-menu/actions/record-actions/components/DeleteRecordsActionEffect'; import { ExportRecordsActionEffect } from '@/action-menu/actions/record-actions/components/ExportRecordsActionEffect'; import { ManageFavoritesActionEffect } from '@/action-menu/actions/record-actions/components/ManageFavoritesActionEffect'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -export const SingleRecordActionMenuEntriesSetter = () => { +export const SingleRecordActionMenuEntriesSetter = ({ + objectMetadataItem, +}: { + objectMetadataItem: ObjectMetadataItem; +}) => { const actionEffects = [ ManageFavoritesActionEffect, ExportRecordsActionEffect, @@ -11,7 +16,11 @@ export const SingleRecordActionMenuEntriesSetter = () => { return ( <> {actionEffects.map((ActionEffect, index) => ( - + ))} ); diff --git a/packages/twenty-front/src/modules/action-menu/components/ActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/ActionMenu.tsx new file mode 100644 index 000000000000..92cda27cc9d8 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/components/ActionMenu.tsx @@ -0,0 +1,30 @@ +import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; +import { ActionMenuBar } from '@/action-menu/components/ActionMenuBar'; +import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; +import { ActionMenuDropdown } from '@/action-menu/components/ActionMenuDropdown'; +import { ActionMenuEffect } from '@/action-menu/components/ActionMenuEffect'; +import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; +import { useRecoilValue } from 'recoil'; + +export const ActionMenu = ({ actionMenuId }: { actionMenuId: string }) => { + const contextStoreCurrentObjectMetadataId = useRecoilValue( + contextStoreCurrentObjectMetadataIdState, + ); + + return ( + <> + {contextStoreCurrentObjectMetadataId && ( + + + + + + + + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/action-menu/components/ActionMenuBar.tsx b/packages/twenty-front/src/modules/action-menu/components/ActionMenuBar.tsx index 258683347919..2fd2937408c0 100644 --- a/packages/twenty-front/src/modules/action-menu/components/ActionMenuBar.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/ActionMenuBar.tsx @@ -4,7 +4,7 @@ import { ActionMenuBarEntry } from '@/action-menu/components/ActionMenuBarEntry' import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { ActionBarHotkeyScope } from '@/action-menu/types/ActionBarHotKeyScope'; -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; +import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; import { BottomBar } from '@/ui/layout/bottom-bar/components/BottomBar'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; @@ -19,8 +19,8 @@ const StyledLabel = styled.div` `; export const ActionMenuBar = () => { - const contextStoreTargetedRecordIds = useRecoilValue( - contextStoreTargetedRecordIdsState, + const contextStoreNumberOfSelectedRecords = useRecoilValue( + contextStoreNumberOfSelectedRecordsState, ); const actionMenuId = useAvailableComponentInstanceIdOrThrow( @@ -42,9 +42,7 @@ export const ActionMenuBar = () => { scope: ActionBarHotkeyScope.ActionBar, }} > - - {contextStoreTargetedRecordIds.length} selected: - + {contextStoreNumberOfSelectedRecords} selected: {actionMenuEntries.map((entry, index) => ( ))} diff --git a/packages/twenty-front/src/modules/action-menu/components/ActionMenuDropdown.tsx b/packages/twenty-front/src/modules/action-menu/components/ActionMenuDropdown.tsx index 18ebdac7667e..c05df9b758a2 100644 --- a/packages/twenty-front/src/modules/action-menu/components/ActionMenuDropdown.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/ActionMenuDropdown.tsx @@ -64,7 +64,7 @@ export const ActionMenuDropdown = () => { return ( { - const contextStoreTargetedRecordIds = useRecoilValue( - contextStoreTargetedRecordIdsState, + const contextStoreNumberOfSelectedRecords = useRecoilValue( + contextStoreNumberOfSelectedRecordsState, ); const actionMenuId = useAvailableComponentInstanceIdOrThrow( @@ -26,17 +26,17 @@ export const ActionMenuEffect = () => { ); useEffect(() => { - if (contextStoreTargetedRecordIds.length > 0 && !isDropdownOpen) { + if (contextStoreNumberOfSelectedRecords > 0 && !isDropdownOpen) { // We only handle opening the ActionMenuBar here, not the Dropdown. // The Dropdown is already managed by sync handlers for events like // right-click to open and click outside to close. openActionBar(); } - if (contextStoreTargetedRecordIds.length === 0) { + if (contextStoreNumberOfSelectedRecords === 0 && isDropdownOpen) { closeActionBar(); } }, [ - contextStoreTargetedRecordIds, + contextStoreNumberOfSelectedRecords, openActionBar, closeActionBar, isDropdownOpen, diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBar.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBar.stories.tsx index 34d709d1685d..b34462d8fb3c 100644 --- a/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBar.stories.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBar.stories.tsx @@ -5,7 +5,8 @@ import { RecoilRoot } from 'recoil'; import { ActionMenuBar } from '@/action-menu/components/ActionMenuBar'; import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; +import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState'; import { userEvent, waitFor, within } from '@storybook/test'; import { IconCheckbox, IconTrash } from 'twenty-ui'; @@ -20,7 +21,11 @@ const meta: Meta = { (Story) => ( { - set(contextStoreTargetedRecordIdsState, ['1', '2', '3']); + set(contextStoreTargetedRecordsRuleState, { + mode: 'selection', + selectedRecordIds: ['1', '2', '3'], + }); + set(contextStoreNumberOfSelectedRecordsState, 3); set( actionMenuEntriesComponentState.atomFamily({ instanceId: 'story-action-menu', diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts b/packages/twenty-front/src/modules/action-menu/hooks/__tests__/useExportRecordData.test.ts similarity index 99% rename from packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts rename to packages/twenty-front/src/modules/action-menu/hooks/__tests__/useExportRecordData.test.ts index 0494fd32f023..65fa9ba2e29c 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/__tests__/useExportRecordData.test.ts @@ -7,7 +7,7 @@ import { displayedExportProgress, download, generateCsv, -} from '../useExportTableData'; +} from '../useExportRecordData'; jest.useFakeTimers(); diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts b/packages/twenty-front/src/modules/action-menu/hooks/useExportRecordData.ts similarity index 91% rename from packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts rename to packages/twenty-front/src/modules/action-menu/hooks/useExportRecordData.ts index 532b8e0aa59b..8fa6d6f5981c 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useExportRecordData.ts @@ -4,10 +4,11 @@ import { useMemo } from 'react'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/record-index/options/constants/ExportTableDataDefaultPageSize'; import { useProcessRecordsForCSVExport } from '@/object-record/record-index/options/hooks/useProcessRecordsForCSVExport'; + import { - useTableData, - UseTableDataOptions, -} from '@/object-record/record-index/options/hooks/useTableData'; + UseRecordDataOptions, + useRecordData, +} from '@/object-record/record-index/options/hooks/useRecordData'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { RelationDefinitionType } from '~/generated-metadata/graphql'; @@ -134,21 +135,22 @@ const downloader = (mimeType: string, generator: GenerateExport) => { export const csvDownloader = downloader('text/csv', generateCsv); -type UseExportTableDataOptions = Omit & { +type UseExportTableDataOptions = Omit & { filename: string; }; -export const useExportTableData = ({ +export const useExportRecordData = ({ delayMs, filename, maximumRequests = 100, - objectNameSingular, + objectMetadataItem, pageSize = EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE, recordIndexId, viewType, }: UseExportTableDataOptions) => { - const { processRecordsForCSVExport } = - useProcessRecordsForCSVExport(objectNameSingular); + const { processRecordsForCSVExport } = useProcessRecordsForCSVExport( + objectMetadataItem.nameSingular, + ); const downloadCsv = useMemo( () => @@ -160,10 +162,10 @@ export const useExportTableData = ({ [filename, processRecordsForCSVExport], ); - const { getTableData: download, progress } = useTableData({ + const { getTableData: download, progress } = useRecordData({ delayMs, maximumRequests, - objectNameSingular, + objectMetadataItem, pageSize, recordIndexId, callback: downloadCsv, diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsState.ts new file mode 100644 index 000000000000..fb1b3544d320 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui'; + +export const contextStoreNumberOfSelectedRecordsState = createState({ + key: 'contextStoreNumberOfSelectedRecordsState', + defaultValue: 0, +}); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordIdsState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordIdsState.ts deleted file mode 100644 index df0c3451172c..000000000000 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordIdsState.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createState } from 'twenty-ui'; - -export const contextStoreTargetedRecordIdsState = createState({ - key: 'contextStoreTargetedRecordIdsState', - defaultValue: [], -}); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleState.ts new file mode 100644 index 000000000000..7f71377c3186 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleState.ts @@ -0,0 +1,26 @@ +import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; +import { createState } from 'twenty-ui'; + +type ContextStoreTargetedRecordsRuleSelectionMode = { + mode: 'selection'; + selectedRecordIds: string[]; +}; + +type ContextStoreTargetedRecordsRuleExclusionMode = { + mode: 'exclusion'; + excludedRecordIds: string[]; + filters: Filter[]; +}; + +export type ContextStoreTargetedRecordsRule = + | ContextStoreTargetedRecordsRuleSelectionMode + | ContextStoreTargetedRecordsRuleExclusionMode; + +export const contextStoreTargetedRecordsRuleState = + createState({ + key: 'contextStoreTargetedRecordsRuleState', + defaultValue: { + mode: 'selection', + selectedRecordIds: [], + }, + }); diff --git a/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts b/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts new file mode 100644 index 000000000000..689d7287d4da --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts @@ -0,0 +1,77 @@ +import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; +import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; +import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; +describe('computeContextStoreFilters', () => { + const personObjectMetadataItem = generatedMockObjectMetadataItems.find( + (item) => item.nameSingular === 'person', + )!; + + it('should work for selection mode', () => { + const contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule = { + mode: 'selection', + selectedRecordIds: ['1', '2', '3'], + }; + + const filters = computeContextStoreFilters( + contextStoreTargetedRecordsRule, + personObjectMetadataItem, + ); + + expect(filters).toEqual({ + id: { + in: ['1', '2', '3'], + }, + }); + }); + + it('should work for exclusion mode', () => { + const contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule = { + mode: 'exclusion', + filters: [ + { + id: 'name-filter', + variant: 'default', + fieldMetadataId: personObjectMetadataItem.fields.find( + (field) => field.name === 'name', + )!.id, + value: 'John', + displayValue: 'John', + displayAvatarUrl: undefined, + operand: ViewFilterOperand.Contains, + definition: { + fieldMetadataId: personObjectMetadataItem.fields.find( + (field) => field.name === 'name', + )!.id, + label: 'Name', + iconName: 'person', + type: 'TEXT', + }, + }, + ], + excludedRecordIds: ['1', '2', '3'], + }; + + const filters = computeContextStoreFilters( + contextStoreTargetedRecordsRule, + personObjectMetadataItem, + ); + + expect(filters).toEqual({ + and: [ + { + name: { + ilike: '%John%', + }, + }, + { + not: { + id: { + in: ['1', '2', '3'], + }, + }, + }, + ], + }); + }); +}); diff --git a/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts b/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts new file mode 100644 index 000000000000..26727fbc26ee --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts @@ -0,0 +1,42 @@ +import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { turnFiltersIntoQueryFilter } from '@/object-record/record-filter/utils/turnFiltersIntoQueryFilter'; +import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables'; + +export const computeContextStoreFilters = ( + contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule, + objectMetadataItem: ObjectMetadataItem, +) => { + let queryFilter: RecordGqlOperationFilter | undefined; + + if (contextStoreTargetedRecordsRule.mode === 'exclusion') { + queryFilter = makeAndFilterVariables([ + turnFiltersIntoQueryFilter( + contextStoreTargetedRecordsRule.filters, + objectMetadataItem?.fields ?? [], + ), + contextStoreTargetedRecordsRule.excludedRecordIds.length > 0 + ? { + not: { + id: { + in: contextStoreTargetedRecordsRule.excludedRecordIds, + }, + }, + } + : undefined, + ]); + } + if (contextStoreTargetedRecordsRule.mode === 'selection') { + queryFilter = + contextStoreTargetedRecordsRule.selectedRecordIds.length > 0 + ? { + id: { + in: contextStoreTargetedRecordsRule.selectedRecordIds, + }, + } + : undefined; + } + + return queryFilter; +}; diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useObjectMetadataItemById.test.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useObjectMetadataItemById.test.ts index ceff2e45541a..01cdbc405d6d 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useObjectMetadataItemById.test.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useObjectMetadataItemById.test.ts @@ -33,16 +33,11 @@ describe('useObjectMetadataItemById', () => { expect(objectMetadataItem?.id).toBe(opportunityObjectMetadata.id); }); - it('should return null when invalid ID is provided', async () => { - const { result } = renderHook( - () => useObjectMetadataItemById({ objectId: 'invalid-id' }), - { + it('should throw an error when invalid ID is provided', async () => { + expect(() => + renderHook(() => useObjectMetadataItemById({ objectId: 'invalid-id' }), { wrapper: Wrapper, - }, - ); - - const { objectMetadataItem } = result.current; - - expect(objectMetadataItem).toBeNull(); + }), + ).toThrow(`Object metadata item not found for id invalid-id`); }); }); diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemById.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemById.ts index 72c559364226..1783ea61fd1b 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemById.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemById.ts @@ -6,7 +6,7 @@ import { isDefined } from '~/utils/isDefined'; export const useObjectMetadataItemById = ({ objectId, }: { - objectId: string | null; + objectId: string; }) => { const objectMetadataItems = useRecoilValue(objectMetadataItemsState); @@ -15,9 +15,7 @@ export const useObjectMetadataItemById = ({ ); if (!isDefined(objectMetadataItem)) { - return { - objectMetadataItem: null, - }; + throw new Error(`Object metadata item not found for id ${objectId}`); } return { diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx index 01ca2843c3bb..592f2d7b4af4 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -66,7 +66,7 @@ export const RecordBoard = () => { useListenClickOutsideByClassName({ classNames: ['record-board-card'], - excludeClassNames: ['bottom-bar', 'context-menu'], + excludeClassNames: ['bottom-bar', 'action-menu-dropdown'], callback: resetRecordSelection, }); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnObjectDropdownFilterIntoQueryFilter.test.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnFiltersIntoQueryFilter.test.ts similarity index 97% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnObjectDropdownFilterIntoQueryFilter.test.ts rename to packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnFiltersIntoQueryFilter.test.ts index 6486ca29b92e..e8778a3f89bb 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnObjectDropdownFilterIntoQueryFilter.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnFiltersIntoQueryFilter.test.ts @@ -1,5 +1,5 @@ import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; -import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; +import { turnFiltersIntoQueryFilter } from '@/object-record/record-filter/utils/turnFiltersIntoQueryFilter'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { getCompaniesMock } from '~/testing/mock-data/companies'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; @@ -16,7 +16,7 @@ const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find( jest.useFakeTimers().setSystemTime(new Date('2020-01-01')); -describe('turnObjectDropdownFilterIntoQueryFilter', () => { +describe('turnFiltersIntoQueryFilter', () => { it('should work as expected for single filter', () => { const companyMockNameFieldMetadataId = companyMockObjectMetadataItem.fields.find( @@ -37,7 +37,7 @@ describe('turnObjectDropdownFilterIntoQueryFilter', () => { }, }; - const result = turnObjectDropdownFilterIntoQueryFilter( + const result = turnFiltersIntoQueryFilter( [nameFilter], companyMockObjectMetadataItem.fields, ); @@ -88,7 +88,7 @@ describe('turnObjectDropdownFilterIntoQueryFilter', () => { }, }; - const result = turnObjectDropdownFilterIntoQueryFilter( + const result = turnFiltersIntoQueryFilter( [nameFilter, employeesFilter], companyMockObjectMetadataItem.fields, ); @@ -173,7 +173,7 @@ describe('should work as expected for the different field types', () => { }, }; - const result = turnObjectDropdownFilterIntoQueryFilter( + const result = turnFiltersIntoQueryFilter( [ addressFilterContains, addressFilterDoesNotContain, @@ -554,7 +554,7 @@ describe('should work as expected for the different field types', () => { }, }; - const result = turnObjectDropdownFilterIntoQueryFilter( + const result = turnFiltersIntoQueryFilter( [ phonesFilterContains, phonesFilterDoesNotContain, @@ -754,7 +754,7 @@ describe('should work as expected for the different field types', () => { }, }; - const result = turnObjectDropdownFilterIntoQueryFilter( + const result = turnFiltersIntoQueryFilter( [ emailsFilterContains, emailsFilterDoesNotContain, @@ -908,7 +908,7 @@ describe('should work as expected for the different field types', () => { }, }; - const result = turnObjectDropdownFilterIntoQueryFilter( + const result = turnFiltersIntoQueryFilter( [ dateFilterIsAfter, dateFilterIsBefore, @@ -1023,7 +1023,7 @@ describe('should work as expected for the different field types', () => { }, }; - const result = turnObjectDropdownFilterIntoQueryFilter( + const result = turnFiltersIntoQueryFilter( [ employeesFilterIsGreaterThan, employeesFilterIsLessThan, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnFiltersIntoQueryFilter.ts similarity index 99% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts rename to packages/twenty-front/src/modules/object-record/record-filter/utils/turnFiltersIntoQueryFilter.ts index 345421f7ce95..0e3c69d7c0b8 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnFiltersIntoQueryFilter.ts @@ -31,7 +31,7 @@ import { z } from 'zod'; // TODO: break this down into smaller functions and make the whole thing immutable // Especially applyEmptyFilters -export const turnObjectDropdownFilterIntoQueryFilter = ( +export const turnFiltersIntoQueryFilter = ( rawUIFilters: Filter[], fields: Pick[], ): RecordGqlOperationFilter | undefined => { diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx index 354abcf09dab..9e8358f9e096 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx @@ -2,8 +2,7 @@ import { useCallback, useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { useRecoilValue, useSetRecoilState } from 'recoil'; -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; @@ -121,32 +120,23 @@ export const RecordIndexBoardDataLoaderEffect = ({ const selectedRecordIds = useRecoilValue(selectedRecordIdsSelector()); - const setContextStoreTargetedRecordIds = useSetRecoilState( - contextStoreTargetedRecordIdsState, + const setContextStoreTargetedRecords = useSetRecoilState( + contextStoreTargetedRecordsRuleState, ); - const setContextStoreCurrentObjectMetadataItem = useSetRecoilState( - contextStoreCurrentObjectMetadataIdState, - ); - - useEffect(() => { - setContextStoreTargetedRecordIds(selectedRecordIds); - }, [selectedRecordIds, setContextStoreTargetedRecordIds]); - useEffect(() => { - setContextStoreTargetedRecordIds(selectedRecordIds); - setContextStoreCurrentObjectMetadataItem(objectMetadataItem?.id); + setContextStoreTargetedRecords({ + mode: 'selection', + selectedRecordIds: selectedRecordIds, + }); return () => { - setContextStoreTargetedRecordIds([]); - setContextStoreCurrentObjectMetadataItem(null); + setContextStoreTargetedRecords({ + mode: 'selection', + selectedRecordIds: [], + }); }; - }, [ - objectMetadataItem?.id, - selectedRecordIds, - setContextStoreCurrentObjectMetadataItem, - setContextStoreTargetedRecordIds, - ]); + }, [selectedRecordIds, setContextStoreTargetedRecords]); return <>; }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx index 9aecee3e6160..a28d2f26ac08 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx @@ -22,12 +22,8 @@ import { RecordFieldValueSelectorContextProvider } from '@/object-record/record- import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider'; -import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; -import { ActionMenuBar } from '@/action-menu/components/ActionMenuBar'; -import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; -import { ActionMenuDropdown } from '@/action-menu/components/ActionMenuDropdown'; -import { ActionMenuEffect } from '@/action-menu/components/ActionMenuEffect'; -import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { ActionMenu } from '@/action-menu/components/ActionMenu'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; import { ViewBar } from '@/views/components/ViewBar'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewField } from '@/views/types/ViewField'; @@ -106,6 +102,10 @@ export const RecordIndexContainer = () => { [columnDefinitions, setTableColumns], ); + const setContextStoreTargetedRecordsRule = useSetRecoilState( + contextStoreTargetedRecordsRuleState, + ); + return ( @@ -119,7 +119,7 @@ export const RecordIndexContainer = () => { optionsDropdownButton={ } @@ -135,6 +135,13 @@ export const RecordIndexContainer = () => { setRecordIndexFilters( mapViewFiltersToFilters(view.viewFilters, filterDefinitions), ); + setContextStoreTargetedRecordsRule((prev) => ({ + ...prev, + filters: mapViewFiltersToFilters( + view.viewFilters, + filterDefinitions, + ), + })); setTableSorts( mapViewSortsToSorts(view.viewSorts, sortDefinitions), ); @@ -179,15 +186,7 @@ export const RecordIndexContainer = () => { /> )} - - - - - - - + diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx new file mode 100644 index 000000000000..2a538c542af1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx @@ -0,0 +1,66 @@ +import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; +import { useFindManyParams } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; +import { useContext, useEffect } from 'react'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; + +export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect = + () => { + const setContextStoreNumberOfSelectedRecords = useSetRecoilState( + contextStoreNumberOfSelectedRecordsState, + ); + + const contextStoreTargetedRecordsRule = useRecoilValue( + contextStoreTargetedRecordsRuleState, + ); + + const { objectNamePlural } = useContext(RecordIndexRootPropsContext); + + const { objectNameSingular } = useObjectNameSingularFromPlural({ + objectNamePlural, + }); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const findManyRecordsParams = useFindManyParams( + objectMetadataItem?.nameSingular ?? '', + objectMetadataItem?.namePlural ?? '', + ); + + const { totalCount } = useFindManyRecords({ + ...findManyRecordsParams, + recordGqlFields: { + id: true, + }, + filter: computeContextStoreFilters( + contextStoreTargetedRecordsRule, + objectMetadataItem, + ), + limit: 1, + skip: contextStoreTargetedRecordsRule.mode === 'selection', + }); + + useEffect(() => { + if (contextStoreTargetedRecordsRule.mode === 'selection') { + setContextStoreNumberOfSelectedRecords( + contextStoreTargetedRecordsRule.selectedRecordIds.length, + ); + } + if (contextStoreTargetedRecordsRule.mode === 'exclusion') { + setContextStoreNumberOfSelectedRecords(totalCount ?? 0); + } + }, [ + contextStoreTargetedRecordsRule, + setContextStoreNumberOfSelectedRecords, + totalCount, + ]); + + return null; + }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect.tsx new file mode 100644 index 000000000000..c94611836a1b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect.tsx @@ -0,0 +1,31 @@ +import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; +import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; +import { useContext, useEffect } from 'react'; +import { useSetRecoilState } from 'recoil'; + +export const RecordIndexContainerContextStoreObjectMetadataEffect = () => { + const setContextStoreCurrentObjectMetadataItem = useSetRecoilState( + contextStoreCurrentObjectMetadataIdState, + ); + const { objectNamePlural } = useContext(RecordIndexRootPropsContext); + + const { objectNameSingular } = useObjectNameSingularFromPlural({ + objectNamePlural, + }); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + useEffect(() => { + setContextStoreCurrentObjectMetadataItem(objectMetadataItem.id); + + return () => { + setContextStoreCurrentObjectMetadataItem(null); + }; + }, [objectMetadataItem.id, setContextStoreCurrentObjectMetadataItem]); + + return null; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx index da407d91e5a9..ba541ca1a67c 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx @@ -1,8 +1,7 @@ import { useContext, useEffect } from 'react'; import { useRecoilValue, useSetRecoilState } from 'recoil'; -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; @@ -24,18 +23,12 @@ export const RecordIndexTableContainerEffect = () => { selectedRowIdsSelector, setOnToggleColumnFilter, setOnToggleColumnSort, + hasUserSelectedAllRowsState, + unselectedRowIdsSelector, } = useRecordTable({ recordTableId: recordIndexId, }); - const setContextStoreTargetedRecordIds = useSetRecoilState( - contextStoreTargetedRecordIdsState, - ); - - const setContextStoreCurrentObjectMetadataItem = useSetRecoilState( - contextStoreCurrentObjectMetadataIdState, - ); - const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); @@ -50,8 +43,6 @@ export const RecordIndexTableContainerEffect = () => { setAvailableTableColumns(columnDefinitions); }, [columnDefinitions, setAvailableTableColumns]); - const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); - const handleToggleColumnFilter = useHandleToggleColumnFilter({ objectNameSingular, viewBarId, @@ -82,19 +73,38 @@ export const RecordIndexTableContainerEffect = () => { ); }, [setRecordCountInCurrentView, setOnEntityCountChange]); + const setContextStoreTargetedRecords = useSetRecoilState( + contextStoreTargetedRecordsRuleState, + ); + const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); + const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); + const unselectedRowIds = useRecoilValue(unselectedRowIdsSelector()); + useEffect(() => { - setContextStoreTargetedRecordIds(selectedRowIds); - setContextStoreCurrentObjectMetadataItem(objectMetadataItem?.id); + if (hasUserSelectedAllRows) { + setContextStoreTargetedRecords({ + mode: 'exclusion', + excludedRecordIds: unselectedRowIds, + filters: [], + }); + } else { + setContextStoreTargetedRecords({ + mode: 'selection', + selectedRecordIds: selectedRowIds, + }); + } return () => { - setContextStoreTargetedRecordIds([]); - setContextStoreCurrentObjectMetadataItem(null); + setContextStoreTargetedRecords({ + mode: 'selection', + selectedRecordIds: [], + }); }; }, [ - objectMetadataItem?.id, + hasUserSelectedAllRows, selectedRowIds, - setContextStoreCurrentObjectMetadataItem, - setContextStoreTargetedRecordIds, + setContextStoreTargetedRecords, + unselectedRowIds, ]); return <>; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts index 297f1dcf8088..3f5ce71ed09b 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts @@ -5,7 +5,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; -import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; +import { turnFiltersIntoQueryFilter } from '@/object-record/record-filter/utils/turnFiltersIntoQueryFilter'; import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields'; import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState'; import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState'; @@ -44,7 +44,7 @@ export const useLoadRecordIndexBoard = ({ const recordIndexFilters = useRecoilValue(recordIndexFiltersState); const recordIndexSorts = useRecoilValue(recordIndexSortsState); - const requestFilters = turnObjectDropdownFilterIntoQueryFilter( + const requestFilters = turnFiltersIntoQueryFilter( recordIndexFilters, objectMetadataItem?.fields ?? [], ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts index 02485fe0d78b..e77545fdcf6f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts @@ -5,7 +5,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; -import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; +import { turnFiltersIntoQueryFilter } from '@/object-record/record-filter/utils/turnFiltersIntoQueryFilter'; import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields'; import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState'; import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState'; @@ -35,7 +35,7 @@ export const useLoadRecordIndexBoardColumn = ({ const recordIndexFilters = useRecoilValue(recordIndexFiltersState); const recordIndexSorts = useRecoilValue(recordIndexSortsState); - const requestFilters = turnObjectDropdownFilterIntoQueryFilter( + const requestFilters = turnFiltersIntoQueryFilter( recordIndexFilters, objectMetadataItem?.fields ?? [], ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts index df178df4c4fd..f39ebc77915b 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts @@ -5,7 +5,7 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; -import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; +import { turnFiltersIntoQueryFilter } from '@/object-record/record-filter/utils/turnFiltersIntoQueryFilter'; import { useRecordTableRecordGqlFields } from '@/object-record/record-index/hooks/useRecordTableRecordGqlFields'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; @@ -27,7 +27,7 @@ export const useFindManyParams = ( const tableFilters = useRecoilValue(tableFiltersState); const tableSorts = useRecoilValue(tableSortsState); - const filter = turnObjectDropdownFilterIntoQueryFilter( + const filter = turnFiltersIntoQueryFilter( tableFilters, objectMetadataItem?.fields ?? [], ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdown.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdown.tsx index 25e53d8cc5b1..3c2f5b2bae3e 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdown.tsx @@ -1,3 +1,4 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { RecordIndexOptionsDropdownButton } from '@/object-record/record-index/options/components/RecordIndexOptionsDropdownButton'; import { RecordIndexOptionsDropdownContent } from '@/object-record/record-index/options/components/RecordIndexOptionsDropdownContent'; import { RECORD_INDEX_OPTIONS_DROPDOWN_ID } from '@/object-record/record-index/options/constants/RecordIndexOptionsDropdownId'; @@ -7,13 +8,13 @@ import { ViewType } from '@/views/types/ViewType'; type RecordIndexOptionsDropdownProps = { viewType: ViewType; - objectNameSingular: string; + objectMetadataItem: ObjectMetadataItem; recordIndexId: string; }; export const RecordIndexOptionsDropdown = ({ recordIndexId, - objectNameSingular, + objectMetadataItem, viewType, }: RecordIndexOptionsDropdownProps) => { return ( @@ -26,7 +27,7 @@ export const RecordIndexOptionsDropdown = ({ dropdownComponents={ } diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx index a884eda8582b..9396d30da07c 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx @@ -14,10 +14,12 @@ import { import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular'; import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; import { RECORD_INDEX_OPTIONS_DROPDOWN_ID } from '@/object-record/record-index/options/constants/RecordIndexOptionsDropdownId'; + import { displayedExportProgress, - useExportTableData, -} from '@/object-record/record-index/options/hooks/useExportTableData'; + useExportRecordData, +} from '@/action-menu/hooks/useExportRecordData'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard'; import { useRecordIndexOptionsForTable } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForTable'; import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope'; @@ -44,14 +46,14 @@ type RecordIndexOptionsMenu = 'fields' | 'hiddenFields'; type RecordIndexOptionsDropdownContentProps = { recordIndexId: string; - objectNameSingular: string; + objectMetadataItem: ObjectMetadataItem; viewType: ViewType; }; export const RecordIndexOptionsDropdownContent = ({ viewType, recordIndexId, - objectNameSingular, + objectMetadataItem, }: RecordIndexOptionsDropdownContentProps) => { const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(); @@ -68,7 +70,7 @@ export const RecordIndexOptionsDropdownContent = ({ }; const { objectNamePlural } = useObjectNamePluralFromSingular({ - objectNameSingular: objectNameSingular, + objectNameSingular: objectMetadataItem.nameSingular, }); const settingsUrl = getSettingsPagePath(SettingsPath.ObjectDetail, { @@ -92,7 +94,7 @@ export const RecordIndexOptionsDropdownContent = ({ const { handleToggleTrashColumnFilter, toggleSoftDeleteFilterState } = useHandleToggleTrashColumnFilter({ - objectNameSingular, + objectNameSingular: objectMetadataItem.nameSingular, viewBarId: recordIndexId, }); @@ -104,7 +106,7 @@ export const RecordIndexOptionsDropdownContent = ({ isCompactModeActive, setAndPersistIsCompactModeActive, } = useRecordIndexOptionsForBoard({ - objectNameSingular, + objectNameSingular: objectMetadataItem.nameSingular, recordBoardId: recordIndexId, viewBarId: recordIndexId, }); @@ -126,12 +128,12 @@ export const RecordIndexOptionsDropdownContent = ({ : handleColumnVisibilityChange; const { openObjectRecordsSpreasheetImportDialog } = - useOpenObjectRecordsSpreasheetImportDialog(objectNameSingular); + useOpenObjectRecordsSpreasheetImportDialog(objectMetadataItem.nameSingular); - const { progress, download } = useExportTableData({ + const { progress, download } = useExportRecordData({ delayMs: 100, - filename: `${objectNameSingular}.csv`, - objectNameSingular, + filename: `${objectMetadataItem.nameSingular}.csv`, + objectMetadataItem, recordIndexId, viewType, }); diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useRecordData.test.tsx similarity index 86% rename from packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx rename to packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useRecordData.test.tsx index aa9f392782f0..9747c2c4e9e1 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useRecordData.test.tsx @@ -1,6 +1,6 @@ import { renderHook, waitFor } from '@testing-library/react'; import { act } from 'react'; -import { percentage, sleep, useTableData } from '../useTableData'; +import { percentage, sleep, useRecordData } from '../useRecordData'; import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; @@ -11,7 +11,7 @@ import { ViewType } from '@/views/types/ViewType'; import { MockedResponse } from '@apollo/client/testing'; import gql from 'graphql-tag'; import { useRecoilValue } from 'recoil'; -import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; +import { getJestMetadataAndApolloMocksAndContextStoreWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; const defaultResponseData = { @@ -127,9 +127,16 @@ const mocks: MockedResponse[] = [ }, ]; -const WrapperWithResponse = getJestMetadataAndApolloMocksWrapper({ - apolloMocks: mocks, -}); +const WrapperWithResponse = getJestMetadataAndApolloMocksAndContextStoreWrapper( + { + apolloMocks: mocks, + contextStoreTargetedRecordsRule: { + mode: 'selection', + selectedRecordIds: [], + }, + contextStoreCurrentObjectMetadataNameSingular: 'person', + }, +); const graphqlEmptyResponse = [ { @@ -145,28 +152,41 @@ const graphqlEmptyResponse = [ }, ]; -const WrapperWithEmptyResponse = getJestMetadataAndApolloMocksWrapper({ - apolloMocks: graphqlEmptyResponse, -}); +const WrapperWithEmptyResponse = + getJestMetadataAndApolloMocksAndContextStoreWrapper({ + apolloMocks: graphqlEmptyResponse, + contextStoreTargetedRecordsRule: { + mode: 'selection', + selectedRecordIds: [], + }, + contextStoreCurrentObjectMetadataNameSingular: 'person', + }); -describe('useTableData', () => { +describe('useRecordData', () => { const recordIndexId = 'people'; - const objectNameSingular = 'person'; + const objectMetadataItem = generatedMockObjectMetadataItems.find( + (item) => item.nameSingular === 'person', + ); + if (!objectMetadataItem) { + throw new Error('Object metadata item not found'); + } describe('data fetching', () => { it('should handle no records', async () => { const callback = jest.fn(); const { result } = renderHook( () => - useTableData({ + useRecordData({ recordIndexId, - objectNameSingular, + objectMetadataItem, pageSize: 30, callback, delayMs: 0, viewType: ViewType.Kanban, }), - { wrapper: WrapperWithEmptyResponse }, + { + wrapper: WrapperWithEmptyResponse, + }, ); await act(async () => { @@ -182,9 +202,9 @@ describe('useTableData', () => { const callback = jest.fn(); const { result } = renderHook( () => - useTableData({ + useRecordData({ recordIndexId, - objectNameSingular, + objectMetadataItem, callback, pageSize: 30, @@ -211,9 +231,9 @@ describe('useTableData', () => { recordIndexId, ); return { - tableData: useTableData({ + tableData: useRecordData({ recordIndexId, - objectNameSingular, + objectMetadataItem, callback, pageSize: 30, maximumRequests: 100, @@ -223,7 +243,7 @@ describe('useTableData', () => { useRecordBoardHook: useRecordBoard(recordIndexId), kanbanFieldName: useRecoilValue(kanbanFieldNameState), kanbanData: useRecordIndexOptionsForBoard({ - objectNameSingular, + objectNameSingular: objectMetadataItem.nameSingular, recordBoardId: recordIndexId, viewBarId: recordIndexId, }), @@ -304,9 +324,9 @@ describe('useTableData', () => { recordIndexId, ); return { - tableData: useTableData({ + tableData: useRecordData({ recordIndexId, - objectNameSingular, + objectMetadataItem, callback, pageSize: 30, maximumRequests: 100, @@ -316,7 +336,7 @@ describe('useTableData', () => { setKanbanFieldName: useRecordBoard(recordIndexId), kanbanFieldName: useRecoilValue(kanbanFieldNameState), kanbanData: useRecordIndexOptionsForBoard({ - objectNameSingular, + objectNameSingular: objectMetadataItem.nameSingular, recordBoardId: recordIndexId, viewBarId: recordIndexId, }), diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useDeleteTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useDeleteTableData.ts deleted file mode 100644 index 345e11453892..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useDeleteTableData.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { useFavorites } from '@/favorites/hooks/useFavorites'; -import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords'; -import { UseTableDataOptions } from '@/object-record/record-index/options/hooks/useTableData'; -import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; - -type UseDeleteTableDataOptions = Pick< - UseTableDataOptions, - 'objectNameSingular' | 'recordIndexId' ->; - -export const useDeleteTableData = ({ - objectNameSingular, - recordIndexId, -}: UseDeleteTableDataOptions) => { - const { resetTableRowSelection } = useRecordTable({ - recordTableId: recordIndexId, - }); - - const { deleteManyRecords } = useDeleteManyRecords({ - objectNameSingular, - }); - const { favorites, deleteFavorite } = useFavorites(); - - const deleteRecords = async (recordIdsToDelete: string[]) => { - resetTableRowSelection(); - - for (const recordIdToDelete of recordIdsToDelete) { - const foundFavorite = favorites?.find( - (favorite) => favorite.recordId === recordIdToDelete, - ); - - if (foundFavorite !== undefined) { - deleteFavorite(foundFavorite.id); - } - } - - await deleteManyRecords(recordIdsToDelete, { - delayInMsBetweenRequests: 50, - }); - }; - - return { deleteTableData: deleteRecords }; -}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordData.ts similarity index 71% rename from packages/twenty-front/src/modules/object-record/record-index/options/hooks/useTableData.ts rename to packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordData.ts index 98294115c5d2..7c65a53105a9 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordData.ts @@ -1,18 +1,21 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useRecoilValue } from 'recoil'; -import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isDefined } from '~/utils/isDefined'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; +import { useFindManyParams } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/record-index/options/constants/ExportTableDataDefaultPageSize'; import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard'; import { ViewType } from '@/views/types/ViewType'; -import { useFindManyParams } from '../../hooks/useLoadRecordIndexTable'; export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -21,10 +24,10 @@ export const percentage = (part: number, whole: number): number => { return Math.round((part / whole) * 100); }; -export type UseTableDataOptions = { +export type UseRecordDataOptions = { delayMs: number; maximumRequests?: number; - objectNameSingular: string; + objectMetadataItem: ObjectMetadataItem; pageSize?: number; recordIndexId: string; callback: ( @@ -40,15 +43,15 @@ type ExportProgress = { displayType: 'percentage' | 'number'; }; -export const useTableData = ({ +export const useRecordData = ({ + objectMetadataItem, delayMs, maximumRequests = 100, - objectNameSingular, pageSize = EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE, recordIndexId, callback, viewType = ViewType.Table, -}: UseTableDataOptions) => { +}: UseRecordDataOptions) => { const [isDownloading, setIsDownloading] = useState(false); const [inflight, setInflight] = useState(false); const [pageCount, setPageCount] = useState(0); @@ -57,15 +60,10 @@ export const useTableData = ({ }); const [previousRecordCount, setPreviousRecordCount] = useState(0); - const { - visibleTableColumnsSelector, - selectedRowIdsSelector, - tableRowIdsState, - hasUserSelectedAllRowsState, - } = useRecordTableStates(recordIndexId); + const { visibleTableColumnsSelector } = useRecordTableStates(recordIndexId); const { hiddenBoardFields } = useRecordIndexOptionsForBoard({ - objectNameSingular, + objectNameSingular: objectMetadataItem.nameSingular, recordBoardId: recordIndexId, viewBarId: recordIndexId, }); @@ -76,61 +74,21 @@ export const useTableData = ({ (column) => column.metadata.fieldName === kanbanFieldMetadataName, ); const columns = useRecoilValue(visibleTableColumnsSelector()); - const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); - - const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); - const tableRowIds = useRecoilValue(tableRowIdsState); - // user has checked select all and then unselected some rows - const userHasUnselectedSomeRows = - hasUserSelectedAllRows && selectedRowIds.length < tableRowIds.length; - - const hasSelectedRows = - selectedRowIds.length > 0 && - !(hasUserSelectedAllRows && selectedRowIds.length === tableRowIds.length); + const contextStoreTargetedRecordsRule = useRecoilValue( + contextStoreTargetedRecordsRuleState, + ); - const unselectedRowIds = useMemo( - () => - userHasUnselectedSomeRows - ? tableRowIds.filter((id) => !selectedRowIds.includes(id)) - : [], - [userHasUnselectedSomeRows, tableRowIds, selectedRowIds], + const queryFilter = computeContextStoreFilters( + contextStoreTargetedRecordsRule, + objectMetadataItem, ); const findManyRecordsParams = useFindManyParams( - objectNameSingular, + objectMetadataItem.nameSingular, recordIndexId, ); - const selectedFindManyParams = { - ...findManyRecordsParams, - filter: { - ...findManyRecordsParams.filter, - id: { - in: selectedRowIds, - }, - }, - }; - - const unselectedFindManyParams = { - ...findManyRecordsParams, - filter: { - ...findManyRecordsParams.filter, - not: { - id: { - in: unselectedRowIds, - }, - }, - }, - }; - - const usedFindManyParams = - hasSelectedRows && !userHasUnselectedSomeRows - ? selectedFindManyParams - : userHasUnselectedSomeRows - ? unselectedFindManyParams - : findManyRecordsParams; - const { findManyRecords, totalCount, @@ -138,7 +96,8 @@ export const useTableData = ({ fetchMoreRecordsWithPagination, loading, } = useLazyFindManyRecords({ - ...usedFindManyParams, + ...findManyRecordsParams, + filter: queryFilter, limit: pageSize, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableInternalEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableInternalEffect.tsx index 0dff4b429dca..828897b3bb1e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableInternalEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableInternalEffect.tsx @@ -1,41 +1,22 @@ import { Key } from 'ts-key-enum'; -import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; -import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; -import { - ClickOutsideMode, - useListenClickOutsideByClassName, -} from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; +import { useListenClickOutsideByClassName } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; type RecordTableInternalEffectProps = { recordTableId: string; - tableBodyRef: React.RefObject; }; export const RecordTableInternalEffect = ({ recordTableId, - tableBodyRef, }: RecordTableInternalEffectProps) => { const { leaveTableFocus, resetTableRowSelection, useMapKeyboardToSoftFocus } = useRecordTable({ recordTableId }); useMapKeyboardToSoftFocus(); - const { useListenClickOutside } = useClickOutsideListener( - SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID, - ); - - useListenClickOutside({ - refs: [tableBodyRef], - callback: () => { - leaveTableFocus(); - }, - mode: ClickOutsideMode.compareHTMLRef, - }); - useScopedHotkeys( [Key.Escape], () => { @@ -46,9 +27,9 @@ export const RecordTableInternalEffect = ({ useListenClickOutsideByClassName({ classNames: ['entity-table-cell'], - excludeClassNames: ['bottom-bar', 'context-menu'], + excludeClassNames: ['bottom-bar', 'action-menu-dropdown'], callback: () => { - resetTableRowSelection(); + leaveTableFocus(); }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx index b7a46e64829d..43bc9c76cf2f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx @@ -87,10 +87,7 @@ export const RecordTableWithWrappers = ({ onDragSelectionChange={setRowSelected} /> - + diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts index 0a52eb083239..fc3f386432aa 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts @@ -6,21 +6,19 @@ import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotV import { TableHotkeyScope } from '../../types/TableHotkeyScope'; +import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection'; import { useCloseCurrentTableCellInEditMode } from './useCloseCurrentTableCellInEditMode'; import { useDisableSoftFocus } from './useDisableSoftFocus'; -import { useSetHasUserSelectedAllRows } from './useSetAllRowSelectedState'; export const useLeaveTableFocus = (recordTableId?: string) => { const disableSoftFocus = useDisableSoftFocus(recordTableId); const closeCurrentCellInEditMode = useCloseCurrentTableCellInEditMode(recordTableId); - const setHasUserSelectedAllRows = useSetHasUserSelectedAllRows(recordTableId); - - const selectAllRows = useSetHasUserSelectedAllRows(recordTableId); - const { isSoftFocusActiveState } = useRecordTableStates(recordTableId); + const resetTableRowSelection = useResetTableRowSelection(recordTableId); + return useRecoilCallback( ({ snapshot }) => () => { @@ -33,6 +31,8 @@ export const useLeaveTableFocus = (recordTableId?: string) => { .getLoadable(currentHotkeyScopeState) .getValue(); + resetTableRowSelection(); + if (!isSoftFocusActive) { return; } @@ -43,15 +43,12 @@ export const useLeaveTableFocus = (recordTableId?: string) => { closeCurrentCellInEditMode(); disableSoftFocus(); - setHasUserSelectedAllRows(false); - selectAllRows(false); }, [ closeCurrentCellInEditMode, disableSoftFocus, isSoftFocusActiveState, - selectAllRows, - setHasUserSelectedAllRows, + resetTableRowSelection, ], ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableStates.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableStates.ts index 106b1174de02..af9bc7f80209 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableStates.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableStates.ts @@ -19,6 +19,7 @@ import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-t import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector'; import { numberOfTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/numberOfTableColumnsComponentSelector'; import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; +import { unselectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; import { softFocusPositionComponentState } from '@/object-record/record-table/states/softFocusPositionComponentState'; import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState'; @@ -134,6 +135,10 @@ export const useRecordTableStates = (recordTableId?: string) => { selectedRowIdsComponentSelector, scopeId, ), + unselectedRowIdsSelector: extractComponentReadOnlySelector( + unselectedRowIdsComponentSelector, + scopeId, + ), visibleTableColumnsSelector: extractComponentReadOnlySelector( visibleTableColumnsComponentSelector, scopeId, diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts index 79deb4693a2c..3bb5dc6ea08a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts @@ -46,17 +46,16 @@ export const useSetRecordTableData = ({ const recordIds = newRecords.map((record) => record.id); if (!isDeeplyEqual(currentRowIds, recordIds)) { - set(tableRowIdsState, recordIds); - } - - if (hasUserSelectedAllRows) { - for (const rowId of recordIds) { - set(isRowSelectedFamilyState(rowId), true); + if (hasUserSelectedAllRows) { + for (const rowId of recordIds) { + set(isRowSelectedFamilyState(rowId), true); + } } - } - set(numberOfTableRowsState, totalCount ?? 0); - onEntityCountChange(totalCount); + set(tableRowIdsState, recordIds); + set(numberOfTableRowsState, totalCount ?? 0); + onEntityCountChange(totalCount); + } }, [ numberOfTableRowsState, diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts index 6cad63df5448..ffd741ec7e75 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts @@ -42,6 +42,7 @@ export const useRecordTable = (props?: useRecordTableProps) => { isRecordTableInitialLoadingState, tableLastRowVisibleState, selectedRowIdsSelector, + unselectedRowIdsSelector, onToggleColumnFilterState, onToggleColumnSortState, pendingRecordIdState, @@ -223,6 +224,7 @@ export const useRecordTable = (props?: useRecordTableProps) => { setSoftFocusPosition, isSomeCellInEditModeState, selectedRowIdsSelector, + unselectedRowIdsSelector, setHasUserSelectedAllRows, setOnToggleColumnFilter, setOnToggleColumnSort, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx index 459211537244..597d38e61dc7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx @@ -1,9 +1,7 @@ import styled from '@emotion/styled'; import { useCallback, useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; import { useSetCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected'; import { Checkbox } from '@/ui/input/components/Checkbox'; @@ -21,19 +19,16 @@ const StyledContainer = styled.div` export const RecordTableCellCheckbox = () => { const { isSelected } = useContext(RecordTableRowContext); - const { recordId } = useContext(RecordTableRowContext); - const { isRowSelectedFamilyState } = useRecordTableStates(); const { setCurrentRowSelected } = useSetCurrentRowSelected(); - const currentRowSelected = useRecoilValue(isRowSelectedFamilyState(recordId)); const handleClick = useCallback(() => { - setCurrentRowSelected(!currentRowSelected); - }, [currentRowSelected, setCurrentRowSelected]); + setCurrentRowSelected(!isSelected); + }, [isSelected, setCurrentRowSelected]); return ( - + ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx index 5bcfd65d67cd..912789351078 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx @@ -37,7 +37,6 @@ export const RecordTableHeaderCheckboxColumn = () => { setHasUserSelectedAllRows(true); selectAllRows(); } else { - setHasUserSelectedAllRows(false); resetTableRowSelection(); } }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector.ts new file mode 100644 index 000000000000..37621eacc0fa --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector.ts @@ -0,0 +1,23 @@ +import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; +import { tableRowIdsComponentState } from '@/object-record/record-table/states/tableRowIdsComponentState'; +import { createComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/createComponentReadOnlySelector'; + +export const unselectedRowIdsComponentSelector = + createComponentReadOnlySelector({ + key: 'unselectedRowIdsComponentSelector', + get: + ({ scopeId }) => + ({ get }) => { + const rowIds = get(tableRowIdsComponentState({ scopeId })); + + return rowIds.filter( + (rowId) => + get( + isRowSelectedComponentFamilyState({ + scopeId, + familyKey: rowId, + }), + ) === false, + ); + }, + }); diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx index 1ce2f5affe9c..6c538fe36209 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx +++ b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx @@ -1,11 +1,9 @@ import styled from '@emotion/styled'; -import { RecordIndexOptionsDropdown } from '@/object-record/record-index/options/components/RecordIndexOptionsDropdown'; import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers'; import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect'; import { ViewBar } from '@/views/components/ViewBar'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -import { ViewType } from '@/views/types/ViewType'; const StyledContainer = styled.div` display: flex; @@ -26,13 +24,7 @@ export const SignInBackgroundMockContainer = () => { {}} - optionsDropdownButton={ - - } + optionsDropdownButton={<>} /> { + + diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPageContextStoreEffect.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPageContextStoreEffect.tsx index a9a5514e285d..080b6d5a48d4 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPageContextStoreEffect.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPageContextStoreEffect.tsx @@ -1,5 +1,6 @@ import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; +import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; +import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; @@ -10,8 +11,8 @@ export const RecordShowPageContextStoreEffect = ({ }: { recordId: string; }) => { - const setContextStoreTargetedRecordIds = useSetRecoilState( - contextStoreTargetedRecordIdsState, + const setContextStoreTargetedRecordsRule = useSetRecoilState( + contextStoreTargetedRecordsRuleState, ); const setContextStoreCurrentObjectMetadataId = useSetRecoilState( @@ -24,19 +25,32 @@ export const RecordShowPageContextStoreEffect = ({ objectNameSingular: objectNameSingular ?? '', }); + const setContextStoreNumberOfSelectedRecords = useSetRecoilState( + contextStoreNumberOfSelectedRecordsState, + ); + useEffect(() => { - setContextStoreTargetedRecordIds([recordId]); + setContextStoreTargetedRecordsRule({ + mode: 'selection', + selectedRecordIds: [recordId], + }); setContextStoreCurrentObjectMetadataId(objectMetadataItem?.id); + setContextStoreNumberOfSelectedRecords(1); return () => { - setContextStoreTargetedRecordIds([]); + setContextStoreTargetedRecordsRule({ + mode: 'selection', + selectedRecordIds: [], + }); setContextStoreCurrentObjectMetadataId(null); + setContextStoreNumberOfSelectedRecords(0); }; }, [ recordId, - setContextStoreTargetedRecordIds, + setContextStoreTargetedRecordsRule, setContextStoreCurrentObjectMetadataId, objectMetadataItem?.id, + setContextStoreNumberOfSelectedRecords, ]); return null; diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPageEffect.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPageEffect.tsx deleted file mode 100644 index e40a00da25ee..000000000000 --- a/packages/twenty-front/src/pages/object-record/RecordShowPageEffect.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; -import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; - -export const RecordShowPageEffect = ({ recordId }: { recordId: string }) => { - const setContextStoreTargetedRecordIds = useSetRecoilState( - contextStoreTargetedRecordIdsState, - ); - - useEffect(() => { - setContextStoreTargetedRecordIds([recordId]); - }, [recordId, setContextStoreTargetedRecordIds]); - - return null; -}; diff --git a/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx b/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx new file mode 100644 index 000000000000..866ebe143e2e --- /dev/null +++ b/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx @@ -0,0 +1,49 @@ +import { ReactNode, useEffect, useState } from 'react'; +import { useSetRecoilState } from 'recoil'; + +import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; +import { + ContextStoreTargetedRecordsRule, + contextStoreTargetedRecordsRuleState, +} from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; + +export const JestContextStoreSetter = ({ + contextStoreTargetedRecordsRule = { + mode: 'selection', + selectedRecordIds: [], + }, + contextStoreCurrentObjectMetadataNameSingular = '', + children, +}: { + contextStoreTargetedRecordsRule?: ContextStoreTargetedRecordsRule; + contextStoreCurrentObjectMetadataNameSingular?: string; + children: ReactNode; +}) => { + const setContextStoreTargetedRecordsRule = useSetRecoilState( + contextStoreTargetedRecordsRuleState, + ); + const setContextStoreCurrentObjectMetadataId = useSetRecoilState( + contextStoreCurrentObjectMetadataIdState, + ); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular: contextStoreCurrentObjectMetadataNameSingular, + }); + + const contextStoreCurrentObjectMetadataId = objectMetadataItem.id; + + const [isLoaded, setIsLoaded] = useState(false); + useEffect(() => { + setContextStoreTargetedRecordsRule(contextStoreTargetedRecordsRule); + setContextStoreCurrentObjectMetadataId(contextStoreCurrentObjectMetadataId); + setIsLoaded(true); + }, [ + setContextStoreTargetedRecordsRule, + setContextStoreCurrentObjectMetadataId, + contextStoreTargetedRecordsRule, + contextStoreCurrentObjectMetadataId, + ]); + + return isLoaded ? <>{children} : null; +}; diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx new file mode 100644 index 000000000000..e674d4282114 --- /dev/null +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx @@ -0,0 +1,37 @@ +import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { MockedResponse } from '@apollo/client/testing'; +import { ReactNode } from 'react'; +import { MutableSnapshot } from 'recoil'; +import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; +import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter'; + +export const getJestMetadataAndApolloMocksAndContextStoreWrapper = ({ + apolloMocks, + onInitializeRecoilSnapshot, + contextStoreTargetedRecordsRule, + contextStoreCurrentObjectMetadataNameSingular, +}: { + apolloMocks: + | readonly MockedResponse, Record>[] + | undefined; + onInitializeRecoilSnapshot?: (snapshot: MutableSnapshot) => void; + contextStoreTargetedRecordsRule?: ContextStoreTargetedRecordsRule; + contextStoreCurrentObjectMetadataNameSingular?: string; +}) => { + const Wrapper = getJestMetadataAndApolloMocksWrapper({ + apolloMocks, + onInitializeRecoilSnapshot, + }); + return ({ children }: { children: ReactNode }) => ( + + + {children} + + + ); +}; From 784770dfe8422f293c0ffca2ed445c6721b8ce53 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Mon, 21 Oct 2024 14:23:57 +0200 Subject: [PATCH 33/38] Disable Github runners front CIs --- .github/workflows/ci-front.yaml | 46 +-------------------------------- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index f42b4d23b334..0d9a5b4dc6ed 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -58,7 +58,7 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' run: npx nx storybook:build twenty-front front-sb-test: - runs-on: ci-8-cores + runs-on: shipfox-8vcpu-ubuntu-2204 timeout-minutes: 60 needs: front-sb-build strategy: @@ -82,50 +82,6 @@ jobs: if: steps.changed-files.outputs.any_changed == 'false' run: echo "No relevant changes. Skipping CI." - - name: Install dependencies - if: steps.changed-files.outputs.any_changed == 'true' - uses: ./.github/workflows/actions/yarn-install - - name: Install Playwright - if: steps.changed-files.outputs.any_changed == 'true' - run: cd packages/twenty-front && npx playwright install - - name: Front / Restore Storybook Task Cache - if: steps.changed-files.outputs.any_changed == 'true' - uses: ./.github/workflows/actions/task-cache - with: - tag: scope:frontend - tasks: storybook:build - - name: Front / Write .env - if: steps.changed-files.outputs.any_changed == 'true' - run: npx nx reset:env twenty-front - - name: Run storybook tests - if: steps.changed-files.outputs.any_changed == 'true' - run: npx nx storybook:serve-and-test:static twenty-front --configuration=${{ matrix.storybook_scope }} - front-sb-test-shipfox: - runs-on: shipfox-8vcpu-ubuntu-2204 - timeout-minutes: 60 - needs: front-sb-build - strategy: - matrix: - storybook_scope: [pages, modules] - env: - REACT_APP_SERVER_BASE_URL: http://localhost:3000 - NX_REJECT_UNKNOWN_LOCAL_CACHE: 0 - steps: - - name: Fetch local actions - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Check for changed files - id: changed-files - uses: tj-actions/changed-files@v11 - with: - files: | - packages/twenty-front/** - - - name: Skip if no relevant changes - if: steps.changed-files.outputs.any_changed == 'false' - run: echo "No relevant changes. Skipping CI." - - name: Install dependencies if: steps.changed-files.outputs.any_changed == 'true' uses: ./.github/workflows/actions/yarn-install From 28c99cbc64786afb1d2b7d03ab0e34b671a33316 Mon Sep 17 00:00:00 2001 From: Prashant Kumar <38308359+Pk9697@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:02:19 +0530 Subject: [PATCH 34/38] fix: use