Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
891d6a375c | ||
|
|
1c0a7029c3 | ||
|
|
613be773cb | ||
|
|
2dd1fffe02 | ||
|
|
e13c9ef46c | ||
|
|
438d502988 | ||
|
|
edc47bd458 | ||
|
|
47bdcb11d8 | ||
|
|
b817bdca02 | ||
|
|
9c07ecd363 | ||
|
|
eb13378760 | ||
|
|
3e699c4458 | ||
|
|
f738961127 | ||
|
|
49aac04b84 | ||
|
|
40c6c63bf5 | ||
|
|
d583984bf0 | ||
|
|
714f149b0c | ||
|
|
194f0963dc | ||
|
|
5fa3094800 | ||
|
|
87f8e5ca19 |
@@ -7,9 +7,7 @@
|
||||
"npm": "please-use-yarn",
|
||||
"yarn": ">=4.0.2"
|
||||
},
|
||||
"keywords": [
|
||||
"twenty-app"
|
||||
],
|
||||
"keywords": [],
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"scripts": {
|
||||
"twenty": "twenty",
|
||||
|
||||
@@ -583,6 +583,7 @@ type ViewField {
|
||||
workspaceId: UUID!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
isActive: Boolean!
|
||||
deletedAt: DateTime
|
||||
isOverridden: Boolean @deprecated(reason: "isOverridden is deprecated")
|
||||
}
|
||||
@@ -691,6 +692,7 @@ type ViewFieldGroup {
|
||||
workspaceId: UUID!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
isActive: Boolean!
|
||||
deletedAt: DateTime
|
||||
viewFields: [ViewField!]!
|
||||
isOverridden: Boolean! @deprecated(reason: "isOverridden is deprecated")
|
||||
@@ -899,6 +901,7 @@ type PageLayoutWidget {
|
||||
conditionalAvailabilityExpression: String
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
isActive: Boolean!
|
||||
deletedAt: DateTime
|
||||
isOverridden: Boolean @deprecated(reason: "isOverridden is deprecated")
|
||||
}
|
||||
@@ -1234,6 +1237,7 @@ type PageLayoutTab {
|
||||
layoutMode: PageLayoutTabLayoutMode
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
isActive: Boolean!
|
||||
deletedAt: DateTime
|
||||
isOverridden: Boolean @deprecated(reason: "isOverridden is deprecated")
|
||||
}
|
||||
@@ -2193,30 +2197,18 @@ type DeletedWorkspaceMember {
|
||||
userWorkspaceId: UUID
|
||||
}
|
||||
|
||||
type BillingEntitlement {
|
||||
key: BillingEntitlementKey!
|
||||
value: Boolean!
|
||||
type Relation {
|
||||
type: RelationType!
|
||||
sourceObjectMetadata: Object!
|
||||
targetObjectMetadata: Object!
|
||||
sourceFieldMetadata: Field!
|
||||
targetFieldMetadata: Field!
|
||||
}
|
||||
|
||||
enum BillingEntitlementKey {
|
||||
SSO
|
||||
CUSTOM_DOMAIN
|
||||
RLS
|
||||
AUDIT_LOGS
|
||||
}
|
||||
|
||||
type DomainRecord {
|
||||
validationType: String!
|
||||
type: String!
|
||||
status: String!
|
||||
key: String!
|
||||
value: String!
|
||||
}
|
||||
|
||||
type DomainValidRecords {
|
||||
id: UUID!
|
||||
domain: String!
|
||||
records: [DomainRecord!]!
|
||||
"""Relation type"""
|
||||
enum RelationType {
|
||||
ONE_TO_MANY
|
||||
MANY_TO_ONE
|
||||
}
|
||||
|
||||
type IndexEdge {
|
||||
@@ -2318,25 +2310,6 @@ type ObjectFieldsConnection {
|
||||
edges: [FieldEdge!]!
|
||||
}
|
||||
|
||||
type UpsertRowLevelPermissionPredicatesResult {
|
||||
predicates: [RowLevelPermissionPredicate!]!
|
||||
predicateGroups: [RowLevelPermissionPredicateGroup!]!
|
||||
}
|
||||
|
||||
type Relation {
|
||||
type: RelationType!
|
||||
sourceObjectMetadata: Object!
|
||||
targetObjectMetadata: Object!
|
||||
sourceFieldMetadata: Field!
|
||||
targetFieldMetadata: Field!
|
||||
}
|
||||
|
||||
"""Relation type"""
|
||||
enum RelationType {
|
||||
ONE_TO_MANY
|
||||
MANY_TO_ONE
|
||||
}
|
||||
|
||||
type FieldConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
@@ -2345,6 +2318,37 @@ type FieldConnection {
|
||||
edges: [FieldEdge!]!
|
||||
}
|
||||
|
||||
type BillingEntitlement {
|
||||
key: BillingEntitlementKey!
|
||||
value: Boolean!
|
||||
}
|
||||
|
||||
enum BillingEntitlementKey {
|
||||
SSO
|
||||
CUSTOM_DOMAIN
|
||||
RLS
|
||||
AUDIT_LOGS
|
||||
}
|
||||
|
||||
type DomainRecord {
|
||||
validationType: String!
|
||||
type: String!
|
||||
status: String!
|
||||
key: String!
|
||||
value: String!
|
||||
}
|
||||
|
||||
type DomainValidRecords {
|
||||
id: UUID!
|
||||
domain: String!
|
||||
records: [DomainRecord!]!
|
||||
}
|
||||
|
||||
type UpsertRowLevelPermissionPredicatesResult {
|
||||
predicates: [RowLevelPermissionPredicate!]!
|
||||
predicateGroups: [RowLevelPermissionPredicateGroup!]!
|
||||
}
|
||||
|
||||
type AuthToken {
|
||||
token: String!
|
||||
expiresAt: DateTime!
|
||||
|
||||
@@ -415,6 +415,7 @@ export interface ViewField {
|
||||
workspaceId: Scalars['UUID']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
isActive: Scalars['Boolean']
|
||||
deletedAt?: Scalars['DateTime']
|
||||
/** @deprecated isOverridden is deprecated */
|
||||
isOverridden?: Scalars['Boolean']
|
||||
@@ -492,6 +493,7 @@ export interface ViewFieldGroup {
|
||||
workspaceId: Scalars['UUID']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
isActive: Scalars['Boolean']
|
||||
deletedAt?: Scalars['DateTime']
|
||||
viewFields: ViewField[]
|
||||
/** @deprecated isOverridden is deprecated */
|
||||
@@ -674,6 +676,7 @@ export interface PageLayoutWidget {
|
||||
conditionalAvailabilityExpression?: Scalars['String']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
isActive: Scalars['Boolean']
|
||||
deletedAt?: Scalars['DateTime']
|
||||
/** @deprecated isOverridden is deprecated */
|
||||
isOverridden?: Scalars['Boolean']
|
||||
@@ -959,6 +962,7 @@ export interface PageLayoutTab {
|
||||
layoutMode?: PageLayoutTabLayoutMode
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
isActive: Scalars['Boolean']
|
||||
deletedAt?: Scalars['DateTime']
|
||||
/** @deprecated isOverridden is deprecated */
|
||||
isOverridden?: Scalars['Boolean']
|
||||
@@ -1879,29 +1883,18 @@ export interface DeletedWorkspaceMember {
|
||||
__typename: 'DeletedWorkspaceMember'
|
||||
}
|
||||
|
||||
export interface BillingEntitlement {
|
||||
key: BillingEntitlementKey
|
||||
value: Scalars['Boolean']
|
||||
__typename: 'BillingEntitlement'
|
||||
export interface Relation {
|
||||
type: RelationType
|
||||
sourceObjectMetadata: Object
|
||||
targetObjectMetadata: Object
|
||||
sourceFieldMetadata: Field
|
||||
targetFieldMetadata: Field
|
||||
__typename: 'Relation'
|
||||
}
|
||||
|
||||
export type BillingEntitlementKey = 'SSO' | 'CUSTOM_DOMAIN' | 'RLS' | 'AUDIT_LOGS'
|
||||
|
||||
export interface DomainRecord {
|
||||
validationType: Scalars['String']
|
||||
type: Scalars['String']
|
||||
status: Scalars['String']
|
||||
key: Scalars['String']
|
||||
value: Scalars['String']
|
||||
__typename: 'DomainRecord'
|
||||
}
|
||||
|
||||
export interface DomainValidRecords {
|
||||
id: Scalars['UUID']
|
||||
domain: Scalars['String']
|
||||
records: DomainRecord[]
|
||||
__typename: 'DomainValidRecords'
|
||||
}
|
||||
/** Relation type */
|
||||
export type RelationType = 'ONE_TO_MANY' | 'MANY_TO_ONE'
|
||||
|
||||
export interface IndexEdge {
|
||||
/** The node containing the Index */
|
||||
@@ -2001,25 +1994,6 @@ export interface ObjectFieldsConnection {
|
||||
__typename: 'ObjectFieldsConnection'
|
||||
}
|
||||
|
||||
export interface UpsertRowLevelPermissionPredicatesResult {
|
||||
predicates: RowLevelPermissionPredicate[]
|
||||
predicateGroups: RowLevelPermissionPredicateGroup[]
|
||||
__typename: 'UpsertRowLevelPermissionPredicatesResult'
|
||||
}
|
||||
|
||||
export interface Relation {
|
||||
type: RelationType
|
||||
sourceObjectMetadata: Object
|
||||
targetObjectMetadata: Object
|
||||
sourceFieldMetadata: Field
|
||||
targetFieldMetadata: Field
|
||||
__typename: 'Relation'
|
||||
}
|
||||
|
||||
|
||||
/** Relation type */
|
||||
export type RelationType = 'ONE_TO_MANY' | 'MANY_TO_ONE'
|
||||
|
||||
export interface FieldConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
@@ -2028,6 +2002,36 @@ export interface FieldConnection {
|
||||
__typename: 'FieldConnection'
|
||||
}
|
||||
|
||||
export interface BillingEntitlement {
|
||||
key: BillingEntitlementKey
|
||||
value: Scalars['Boolean']
|
||||
__typename: 'BillingEntitlement'
|
||||
}
|
||||
|
||||
export type BillingEntitlementKey = 'SSO' | 'CUSTOM_DOMAIN' | 'RLS' | 'AUDIT_LOGS'
|
||||
|
||||
export interface DomainRecord {
|
||||
validationType: Scalars['String']
|
||||
type: Scalars['String']
|
||||
status: Scalars['String']
|
||||
key: Scalars['String']
|
||||
value: Scalars['String']
|
||||
__typename: 'DomainRecord'
|
||||
}
|
||||
|
||||
export interface DomainValidRecords {
|
||||
id: Scalars['UUID']
|
||||
domain: Scalars['String']
|
||||
records: DomainRecord[]
|
||||
__typename: 'DomainValidRecords'
|
||||
}
|
||||
|
||||
export interface UpsertRowLevelPermissionPredicatesResult {
|
||||
predicates: RowLevelPermissionPredicate[]
|
||||
predicateGroups: RowLevelPermissionPredicateGroup[]
|
||||
__typename: 'UpsertRowLevelPermissionPredicatesResult'
|
||||
}
|
||||
|
||||
export interface AuthToken {
|
||||
token: Scalars['String']
|
||||
expiresAt: Scalars['DateTime']
|
||||
@@ -3631,6 +3635,7 @@ export interface ViewFieldGenqlSelection{
|
||||
workspaceId?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
isActive?: boolean | number
|
||||
deletedAt?: boolean | number
|
||||
/** @deprecated isOverridden is deprecated */
|
||||
isOverridden?: boolean | number
|
||||
@@ -3705,6 +3710,7 @@ export interface ViewFieldGroupGenqlSelection{
|
||||
workspaceId?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
isActive?: boolean | number
|
||||
deletedAt?: boolean | number
|
||||
viewFields?: ViewFieldGenqlSelection
|
||||
/** @deprecated isOverridden is deprecated */
|
||||
@@ -3879,6 +3885,7 @@ export interface PageLayoutWidgetGenqlSelection{
|
||||
conditionalAvailabilityExpression?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
isActive?: boolean | number
|
||||
deletedAt?: boolean | number
|
||||
/** @deprecated isOverridden is deprecated */
|
||||
isOverridden?: boolean | number
|
||||
@@ -4191,6 +4198,7 @@ export interface PageLayoutTabGenqlSelection{
|
||||
layoutMode?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
isActive?: boolean | number
|
||||
deletedAt?: boolean | number
|
||||
/** @deprecated isOverridden is deprecated */
|
||||
isOverridden?: boolean | number
|
||||
@@ -5149,27 +5157,12 @@ export interface DeletedWorkspaceMemberGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface BillingEntitlementGenqlSelection{
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface DomainRecordGenqlSelection{
|
||||
validationType?: boolean | number
|
||||
export interface RelationGenqlSelection{
|
||||
type?: boolean | number
|
||||
status?: boolean | number
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface DomainValidRecordsGenqlSelection{
|
||||
id?: boolean | number
|
||||
domain?: boolean | number
|
||||
records?: DomainRecordGenqlSelection
|
||||
sourceObjectMetadata?: ObjectGenqlSelection
|
||||
targetObjectMetadata?: ObjectGenqlSelection
|
||||
sourceFieldMetadata?: FieldGenqlSelection
|
||||
targetFieldMetadata?: FieldGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
@@ -5284,23 +5277,6 @@ export interface ObjectFieldsConnectionGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface UpsertRowLevelPermissionPredicatesResultGenqlSelection{
|
||||
predicates?: RowLevelPermissionPredicateGenqlSelection
|
||||
predicateGroups?: RowLevelPermissionPredicateGroupGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface RelationGenqlSelection{
|
||||
type?: boolean | number
|
||||
sourceObjectMetadata?: ObjectGenqlSelection
|
||||
targetObjectMetadata?: ObjectGenqlSelection
|
||||
sourceFieldMetadata?: FieldGenqlSelection
|
||||
targetFieldMetadata?: FieldGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface FieldConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
@@ -5310,6 +5286,38 @@ export interface FieldConnectionGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface BillingEntitlementGenqlSelection{
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface DomainRecordGenqlSelection{
|
||||
validationType?: boolean | number
|
||||
type?: boolean | number
|
||||
status?: boolean | number
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface DomainValidRecordsGenqlSelection{
|
||||
id?: boolean | number
|
||||
domain?: boolean | number
|
||||
records?: DomainRecordGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface UpsertRowLevelPermissionPredicatesResultGenqlSelection{
|
||||
predicates?: RowLevelPermissionPredicateGenqlSelection
|
||||
predicateGroups?: RowLevelPermissionPredicateGroupGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface AuthTokenGenqlSelection{
|
||||
token?: boolean | number
|
||||
expiresAt?: boolean | number
|
||||
@@ -8232,26 +8240,10 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const BillingEntitlement_possibleTypes: string[] = ['BillingEntitlement']
|
||||
export const isBillingEntitlement = (obj?: { __typename?: any } | null): obj is BillingEntitlement => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingEntitlement"')
|
||||
return BillingEntitlement_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DomainRecord_possibleTypes: string[] = ['DomainRecord']
|
||||
export const isDomainRecord = (obj?: { __typename?: any } | null): obj is DomainRecord => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isDomainRecord"')
|
||||
return DomainRecord_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DomainValidRecords_possibleTypes: string[] = ['DomainValidRecords']
|
||||
export const isDomainValidRecords = (obj?: { __typename?: any } | null): obj is DomainValidRecords => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isDomainValidRecords"')
|
||||
return DomainValidRecords_possibleTypes.includes(obj.__typename)
|
||||
const Relation_possibleTypes: string[] = ['Relation']
|
||||
export const isRelation = (obj?: { __typename?: any } | null): obj is Relation => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isRelation"')
|
||||
return Relation_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
@@ -8352,22 +8344,6 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const UpsertRowLevelPermissionPredicatesResult_possibleTypes: string[] = ['UpsertRowLevelPermissionPredicatesResult']
|
||||
export const isUpsertRowLevelPermissionPredicatesResult = (obj?: { __typename?: any } | null): obj is UpsertRowLevelPermissionPredicatesResult => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isUpsertRowLevelPermissionPredicatesResult"')
|
||||
return UpsertRowLevelPermissionPredicatesResult_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const Relation_possibleTypes: string[] = ['Relation']
|
||||
export const isRelation = (obj?: { __typename?: any } | null): obj is Relation => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isRelation"')
|
||||
return Relation_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const FieldConnection_possibleTypes: string[] = ['FieldConnection']
|
||||
export const isFieldConnection = (obj?: { __typename?: any } | null): obj is FieldConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isFieldConnection"')
|
||||
@@ -8376,6 +8352,38 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const BillingEntitlement_possibleTypes: string[] = ['BillingEntitlement']
|
||||
export const isBillingEntitlement = (obj?: { __typename?: any } | null): obj is BillingEntitlement => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingEntitlement"')
|
||||
return BillingEntitlement_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DomainRecord_possibleTypes: string[] = ['DomainRecord']
|
||||
export const isDomainRecord = (obj?: { __typename?: any } | null): obj is DomainRecord => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isDomainRecord"')
|
||||
return DomainRecord_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DomainValidRecords_possibleTypes: string[] = ['DomainValidRecords']
|
||||
export const isDomainValidRecords = (obj?: { __typename?: any } | null): obj is DomainValidRecords => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isDomainValidRecords"')
|
||||
return DomainValidRecords_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const UpsertRowLevelPermissionPredicatesResult_possibleTypes: string[] = ['UpsertRowLevelPermissionPredicatesResult']
|
||||
export const isUpsertRowLevelPermissionPredicatesResult = (obj?: { __typename?: any } | null): obj is UpsertRowLevelPermissionPredicatesResult => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isUpsertRowLevelPermissionPredicatesResult"')
|
||||
return UpsertRowLevelPermissionPredicatesResult_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AuthToken_possibleTypes: string[] = ['AuthToken']
|
||||
export const isAuthToken = (obj?: { __typename?: any } | null): obj is AuthToken => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isAuthToken"')
|
||||
@@ -9576,6 +9584,11 @@ export const enumQueueMetricsTimeRange = {
|
||||
OneHour: 'OneHour' as const
|
||||
}
|
||||
|
||||
export const enumRelationType = {
|
||||
ONE_TO_MANY: 'ONE_TO_MANY' as const,
|
||||
MANY_TO_ONE: 'MANY_TO_ONE' as const
|
||||
}
|
||||
|
||||
export const enumBillingEntitlementKey = {
|
||||
SSO: 'SSO' as const,
|
||||
CUSTOM_DOMAIN: 'CUSTOM_DOMAIN' as const,
|
||||
@@ -9583,11 +9596,6 @@ export const enumBillingEntitlementKey = {
|
||||
AUDIT_LOGS: 'AUDIT_LOGS' as const
|
||||
}
|
||||
|
||||
export const enumRelationType = {
|
||||
ONE_TO_MANY: 'ONE_TO_MANY' as const,
|
||||
MANY_TO_ONE: 'MANY_TO_ONE' as const
|
||||
}
|
||||
|
||||
export const enumEmailingDomainDriver = {
|
||||
AWS_SES: 'AWS_SES' as const
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ export default {
|
||||
209,
|
||||
221,
|
||||
238,
|
||||
255,
|
||||
253,
|
||||
292,
|
||||
293,
|
||||
303,
|
||||
@@ -789,10 +789,10 @@ export default {
|
||||
3
|
||||
],
|
||||
"relation": [
|
||||
254
|
||||
237
|
||||
],
|
||||
"morphRelations": [
|
||||
254
|
||||
237
|
||||
],
|
||||
"object": [
|
||||
46
|
||||
@@ -851,7 +851,7 @@ export default {
|
||||
36
|
||||
],
|
||||
"objectMetadata": [
|
||||
247,
|
||||
245,
|
||||
{
|
||||
"paging": [
|
||||
39,
|
||||
@@ -864,7 +864,7 @@ export default {
|
||||
}
|
||||
],
|
||||
"indexFieldMetadatas": [
|
||||
245,
|
||||
243,
|
||||
{
|
||||
"paging": [
|
||||
39,
|
||||
@@ -1109,7 +1109,7 @@ export default {
|
||||
37
|
||||
],
|
||||
"fields": [
|
||||
252,
|
||||
250,
|
||||
{
|
||||
"paging": [
|
||||
39,
|
||||
@@ -1122,7 +1122,7 @@ export default {
|
||||
}
|
||||
],
|
||||
"indexMetadatas": [
|
||||
250,
|
||||
248,
|
||||
{
|
||||
"paging": [
|
||||
39,
|
||||
@@ -1283,6 +1283,9 @@ export default {
|
||||
"updatedAt": [
|
||||
4
|
||||
],
|
||||
"isActive": [
|
||||
6
|
||||
],
|
||||
"deletedAt": [
|
||||
4
|
||||
],
|
||||
@@ -1456,6 +1459,9 @@ export default {
|
||||
"updatedAt": [
|
||||
4
|
||||
],
|
||||
"isActive": [
|
||||
6
|
||||
],
|
||||
"deletedAt": [
|
||||
4
|
||||
],
|
||||
@@ -1703,7 +1709,7 @@ export default {
|
||||
131
|
||||
],
|
||||
"billingEntitlements": [
|
||||
237
|
||||
252
|
||||
],
|
||||
"hasValidEnterpriseKey": [
|
||||
6
|
||||
@@ -1903,6 +1909,9 @@ export default {
|
||||
"updatedAt": [
|
||||
4
|
||||
],
|
||||
"isActive": [
|
||||
6
|
||||
],
|
||||
"deletedAt": [
|
||||
4
|
||||
],
|
||||
@@ -2561,6 +2570,9 @@ export default {
|
||||
"updatedAt": [
|
||||
4
|
||||
],
|
||||
"isActive": [
|
||||
6
|
||||
],
|
||||
"deletedAt": [
|
||||
4
|
||||
],
|
||||
@@ -4419,9 +4431,179 @@ export default {
|
||||
1
|
||||
]
|
||||
},
|
||||
"Relation": {
|
||||
"type": [
|
||||
238
|
||||
],
|
||||
"sourceObjectMetadata": [
|
||||
46
|
||||
],
|
||||
"targetObjectMetadata": [
|
||||
46
|
||||
],
|
||||
"sourceFieldMetadata": [
|
||||
34
|
||||
],
|
||||
"targetFieldMetadata": [
|
||||
34
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"RelationType": {},
|
||||
"IndexEdge": {
|
||||
"node": [
|
||||
37
|
||||
],
|
||||
"cursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"PageInfo": {
|
||||
"hasNextPage": [
|
||||
6
|
||||
],
|
||||
"hasPreviousPage": [
|
||||
6
|
||||
],
|
||||
"startCursor": [
|
||||
40
|
||||
],
|
||||
"endCursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexConnection": {
|
||||
"pageInfo": [
|
||||
240
|
||||
],
|
||||
"edges": [
|
||||
239
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexFieldEdge": {
|
||||
"node": [
|
||||
36
|
||||
],
|
||||
"cursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexIndexFieldMetadatasConnection": {
|
||||
"pageInfo": [
|
||||
240
|
||||
],
|
||||
"edges": [
|
||||
242
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectEdge": {
|
||||
"node": [
|
||||
46
|
||||
],
|
||||
"cursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexObjectMetadataConnection": {
|
||||
"pageInfo": [
|
||||
240
|
||||
],
|
||||
"edges": [
|
||||
244
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectRecordCount": {
|
||||
"objectNamePlural": [
|
||||
1
|
||||
],
|
||||
"totalCount": [
|
||||
21
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectConnection": {
|
||||
"pageInfo": [
|
||||
240
|
||||
],
|
||||
"edges": [
|
||||
244
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectIndexMetadatasConnection": {
|
||||
"pageInfo": [
|
||||
240
|
||||
],
|
||||
"edges": [
|
||||
239
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"FieldEdge": {
|
||||
"node": [
|
||||
34
|
||||
],
|
||||
"cursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectFieldsConnection": {
|
||||
"pageInfo": [
|
||||
240
|
||||
],
|
||||
"edges": [
|
||||
249
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"FieldConnection": {
|
||||
"pageInfo": [
|
||||
240
|
||||
],
|
||||
"edges": [
|
||||
249
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"BillingEntitlement": {
|
||||
"key": [
|
||||
238
|
||||
253
|
||||
],
|
||||
"value": [
|
||||
6
|
||||
@@ -4459,145 +4641,7 @@ export default {
|
||||
1
|
||||
],
|
||||
"records": [
|
||||
239
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexEdge": {
|
||||
"node": [
|
||||
37
|
||||
],
|
||||
"cursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"PageInfo": {
|
||||
"hasNextPage": [
|
||||
6
|
||||
],
|
||||
"hasPreviousPage": [
|
||||
6
|
||||
],
|
||||
"startCursor": [
|
||||
40
|
||||
],
|
||||
"endCursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexConnection": {
|
||||
"pageInfo": [
|
||||
242
|
||||
],
|
||||
"edges": [
|
||||
241
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexFieldEdge": {
|
||||
"node": [
|
||||
36
|
||||
],
|
||||
"cursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexIndexFieldMetadatasConnection": {
|
||||
"pageInfo": [
|
||||
242
|
||||
],
|
||||
"edges": [
|
||||
244
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectEdge": {
|
||||
"node": [
|
||||
46
|
||||
],
|
||||
"cursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"IndexObjectMetadataConnection": {
|
||||
"pageInfo": [
|
||||
242
|
||||
],
|
||||
"edges": [
|
||||
246
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectRecordCount": {
|
||||
"objectNamePlural": [
|
||||
1
|
||||
],
|
||||
"totalCount": [
|
||||
21
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectConnection": {
|
||||
"pageInfo": [
|
||||
242
|
||||
],
|
||||
"edges": [
|
||||
246
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectIndexMetadatasConnection": {
|
||||
"pageInfo": [
|
||||
242
|
||||
],
|
||||
"edges": [
|
||||
241
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"FieldEdge": {
|
||||
"node": [
|
||||
34
|
||||
],
|
||||
"cursor": [
|
||||
40
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"ObjectFieldsConnection": {
|
||||
"pageInfo": [
|
||||
242
|
||||
],
|
||||
"edges": [
|
||||
251
|
||||
254
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
@@ -4614,38 +4658,6 @@ export default {
|
||||
1
|
||||
]
|
||||
},
|
||||
"Relation": {
|
||||
"type": [
|
||||
255
|
||||
],
|
||||
"sourceObjectMetadata": [
|
||||
46
|
||||
],
|
||||
"targetObjectMetadata": [
|
||||
46
|
||||
],
|
||||
"sourceFieldMetadata": [
|
||||
34
|
||||
],
|
||||
"targetFieldMetadata": [
|
||||
34
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"RelationType": {},
|
||||
"FieldConnection": {
|
||||
"pageInfo": [
|
||||
242
|
||||
],
|
||||
"edges": [
|
||||
251
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"AuthToken": {
|
||||
"token": [
|
||||
1
|
||||
@@ -5975,7 +5987,7 @@ export default {
|
||||
},
|
||||
"AgentChatThreadConnection": {
|
||||
"pageInfo": [
|
||||
242
|
||||
240
|
||||
],
|
||||
"edges": [
|
||||
335
|
||||
@@ -6582,7 +6594,7 @@ export default {
|
||||
}
|
||||
],
|
||||
"objectRecordCounts": [
|
||||
248
|
||||
246
|
||||
],
|
||||
"object": [
|
||||
46,
|
||||
@@ -6594,7 +6606,7 @@ export default {
|
||||
}
|
||||
],
|
||||
"objects": [
|
||||
249,
|
||||
247,
|
||||
{
|
||||
"paging": [
|
||||
39,
|
||||
@@ -6616,7 +6628,7 @@ export default {
|
||||
}
|
||||
],
|
||||
"indexMetadatas": [
|
||||
243,
|
||||
241,
|
||||
{
|
||||
"paging": [
|
||||
39,
|
||||
@@ -6665,7 +6677,7 @@ export default {
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
256,
|
||||
251,
|
||||
{
|
||||
"paging": [
|
||||
39,
|
||||
@@ -8340,7 +8352,7 @@ export default {
|
||||
}
|
||||
],
|
||||
"upsertRowLevelPermissionPredicates": [
|
||||
253,
|
||||
256,
|
||||
{
|
||||
"input": [
|
||||
456,
|
||||
@@ -9082,7 +9094,7 @@ export default {
|
||||
66
|
||||
],
|
||||
"checkCustomDomainValidRecords": [
|
||||
240
|
||||
255
|
||||
],
|
||||
"createOIDCIdentityProvider": [
|
||||
232,
|
||||
@@ -9415,7 +9427,7 @@ export default {
|
||||
}
|
||||
],
|
||||
"checkPublicDomainValidRecords": [
|
||||
240,
|
||||
255,
|
||||
{
|
||||
"domain": [
|
||||
1,
|
||||
|
||||
@@ -87,7 +87,7 @@ Publishing to npm makes your app discoverable in the Twenty marketplace. Any Twe
|
||||
### Requirements
|
||||
|
||||
- An [npm](https://www.npmjs.com) account
|
||||
- The `twenty-app` keyword in your `package.json` `keywords` array (already included when you scaffold with `create-twenty-app`)
|
||||
- The `twenty-app` keyword in your `package.json` `keywords` array (add it manually — it is not included by default in the `create-twenty-app` template)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ yarn twenty deploy
|
||||
### المتطلبات
|
||||
|
||||
* حساب على [npm](https://www.npmjs.com)
|
||||
* الكلمة المفتاحية `twenty-app` في مصفوفة `keywords` في `package.json` (موجودة مسبقًا عند تهيئة المشروع باستخدام `create-twenty-app`)
|
||||
* الكلمة المفتاحية `twenty-app` في مصفوفة `keywords` في `package.json` (أضفها يدويًا — فهي غير مضمنة افتراضيًا في قالب `create-twenty-app`)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ Publikování na npm zajistí, že bude vaše aplikace dohledatelná v Marketpla
|
||||
### Požadavky
|
||||
|
||||
* Účet na [npm](https://www.npmjs.com)
|
||||
* Klíčové slovo `twenty-app` ve vašem poli `keywords` v souboru `package.json` (již je zahrnuto, když založíte projekt pomocí `create-twenty-app`)
|
||||
* Klíčové slovo `twenty-app` ve vašem poli `keywords` v souboru `package.json` (přidejte je ručně — ve výchozím nastavení není zahrnuto v šabloně `create-twenty-app`)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ Die Veröffentlichung auf npm macht Ihre App im Twenty-Marktplatz auffindbar. Je
|
||||
### Anforderungen
|
||||
|
||||
* Ein [npm](https://www.npmjs.com)-Konto
|
||||
* Das Schlüsselwort `twenty-app` in Ihrem `package.json`-Array `keywords` (bereits enthalten, wenn Sie mit `create-twenty-app` ein Gerüst erstellen)
|
||||
* Das Schlüsselwort `twenty-app` in Ihrem `package.json`-Array `keywords` (manuell hinzufügen — es ist in der `create-twenty-app`-Vorlage standardmäßig nicht enthalten)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ La pubblicazione su npm rende la tua app scopribile nel marketplace di Twenty. Q
|
||||
### Requisiti
|
||||
|
||||
* Un account [npm](https://www.npmjs.com)
|
||||
* La parola chiave `twenty-app` nell'array `keywords` del tuo `package.json` (già inclusa quando inizializzi con `create-twenty-app`)
|
||||
* La parola chiave `twenty-app` nell'array `keywords` del tuo `package.json` (aggiungila manualmente — non è inclusa per impostazione predefinita nel template `create-twenty-app`)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ Publicar no npm torna seu aplicativo descobrível no Marketplace da Twenty. Qual
|
||||
### Requisitos
|
||||
|
||||
* Uma conta no [npm](https://www.npmjs.com)
|
||||
* A palavra-chave `twenty-app` no array `keywords` do seu `package.json` (já incluída quando você cria o projeto com `create-twenty-app`)
|
||||
* A palavra-chave `twenty-app` no array `keywords` do seu `package.json` (adicione-a manualmente — não é incluída por padrão no template `create-twenty-app`)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ When updating an already deployed tarball app, the server requires the `version`
|
||||
### Требования
|
||||
|
||||
* Учётная запись [npm](https://www.npmjs.com)
|
||||
* Ключевое слово `twenty-app` в массиве `keywords` вашего `package.json` (уже добавлено при создании проекта с помощью `create-twenty-app`)
|
||||
* Ключевое слово `twenty-app` в массиве `keywords` вашего `package.json` (добавьте его вручную — по умолчанию оно не включено в шаблон `create-twenty-app`)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ npm’ye yayımlamak, uygulamanızın Twenty pazaryerinde keşfedilebilir olmas
|
||||
### Gereksinimler
|
||||
|
||||
* Bir [npm](https://www.npmjs.com) hesabı
|
||||
* `package.json` içindeki `keywords` dizinizdeki `twenty-app` anahtar sözcüğü (`create-twenty-app` ile iskelet oluşturduğunuzda zaten eklenir)
|
||||
* `package.json` içindeki `keywords` dizinizdeki `twenty-app` anahtar sözcüğü (elle ekleyin — varsayılan olarak `create-twenty-app` şablonunda yer almaz)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
@@ -14,6 +14,7 @@ export const PAGE_LAYOUT_TAB_FRAGMENT = gql`
|
||||
...PageLayoutWidgetFragment
|
||||
}
|
||||
pageLayoutId
|
||||
isActive
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
|
||||
@@ -79,7 +79,9 @@ export const splitViewWithRelated = (
|
||||
const { viewFields: _viewFields, ...viewFieldGroupProperties } =
|
||||
viewFieldGroup;
|
||||
|
||||
flatViewFieldGroups.push(viewFieldGroupProperties);
|
||||
flatViewFieldGroups.push({
|
||||
...viewFieldGroupProperties,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -48,6 +48,7 @@ export const RecordBoardCardCellHoveredPortalContent = () => {
|
||||
fieldDefinition,
|
||||
recordId,
|
||||
prefix: RECORD_BOARD_CARD_INPUT_ID_PREFIX,
|
||||
onFileUploadClose: () => setRecordBoardCardEditModePosition(null),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+1
@@ -48,6 +48,7 @@ export const RecordCalendarCardCellHoveredPortalContent = () => {
|
||||
fieldDefinition,
|
||||
recordId,
|
||||
prefix: RECORD_CALENDAR_CARD_INPUT_ID_PREFIX,
|
||||
onFileUploadClose: () => setRecordCalendarCardEditModePosition(null),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+1
@@ -52,6 +52,7 @@ export const RecordFieldListCellHoveredPortalContent = () => {
|
||||
fieldDefinition,
|
||||
recordId,
|
||||
prefix: instanceId,
|
||||
onFileUploadClose: () => setRecordFieldListCellEditModePosition(null),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+3
@@ -66,10 +66,12 @@ export const useOpenFieldInputEditMode = () => {
|
||||
fieldDefinition,
|
||||
recordId,
|
||||
prefix,
|
||||
onFileUploadClose,
|
||||
}: {
|
||||
fieldDefinition: FieldDefinition<FieldMetadata>;
|
||||
recordId: string;
|
||||
prefix?: string;
|
||||
onFileUploadClose?: () => void;
|
||||
}) => {
|
||||
const objectMetadataItems = store.get(objectMetadataItemsSelector.atom);
|
||||
|
||||
@@ -106,6 +108,7 @@ export const useOpenFieldInputEditMode = () => {
|
||||
updateOneRecordInput: updateInput,
|
||||
});
|
||||
},
|
||||
onFileUploadClose,
|
||||
fieldDefinition: {
|
||||
metadata: {
|
||||
settings: fieldDefinition.metadata.settings ?? undefined,
|
||||
|
||||
+5
-62
@@ -4,16 +4,10 @@ import { uploadMultipleFiles } from '@/object-record/record-field/ui/meta-types/
|
||||
import { filesFieldUploadState } from '@/object-record/record-field/ui/states/filesFieldUploadState';
|
||||
import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
|
||||
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { useRemoveLastFocusItemFromFocusStackByComponentType } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackByComponentType';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
|
||||
import { useStore } from 'jotai';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useCallback } from 'react';
|
||||
@@ -24,13 +18,6 @@ export const useOpenFilesFieldInput = () => {
|
||||
const { openFileUpload } = useFileUpload();
|
||||
const { uploadFile } = useUploadFilesFieldFile();
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
const { removeLastFocusItemFromFocusStackByComponentType } =
|
||||
useRemoveLastFocusItemFromFocusStackByComponentType();
|
||||
const { goBackToPreviousDropdownFocusId } =
|
||||
useGoBackToPreviousDropdownFocusId();
|
||||
const recordTableId = useAvailableComponentInstanceId(
|
||||
RecordTableComponentInstanceContext,
|
||||
);
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { t } = useLingui();
|
||||
const store = useStore();
|
||||
@@ -42,7 +29,7 @@ export const useOpenFilesFieldInput = () => {
|
||||
recordId,
|
||||
prefix,
|
||||
updateRecord,
|
||||
onClose,
|
||||
onFileUploadClose,
|
||||
fieldDefinition,
|
||||
}: {
|
||||
fieldName: string;
|
||||
@@ -50,7 +37,7 @@ export const useOpenFilesFieldInput = () => {
|
||||
recordId: string;
|
||||
prefix?: string;
|
||||
updateRecord: (updateInput: Record<string, unknown>) => void;
|
||||
onClose?: () => void;
|
||||
onFileUploadClose?: () => void;
|
||||
fieldDefinition?: {
|
||||
metadata: {
|
||||
settings?: {
|
||||
@@ -86,8 +73,6 @@ export const useOpenFilesFieldInput = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const isTableContext = prefix === RECORD_TABLE_CELL_INPUT_ID_PREFIX;
|
||||
|
||||
const maxNumberOfValues =
|
||||
fieldDefinition?.metadata?.settings?.maxNumberOfValues ??
|
||||
MULTI_ITEM_FIELD_DEFAULT_MAX_VALUES;
|
||||
@@ -112,20 +97,7 @@ export const useOpenFilesFieldInput = () => {
|
||||
null,
|
||||
);
|
||||
|
||||
if (isTableContext && isDefined(recordTableId)) {
|
||||
store.set(
|
||||
recordTableCellEditModePositionComponentState.atomFamily({
|
||||
instanceId: recordTableId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
goBackToPreviousDropdownFocusId();
|
||||
removeLastFocusItemFromFocusStackByComponentType({
|
||||
componentType: FocusComponentType.OPENED_FIELD_INPUT,
|
||||
});
|
||||
} else {
|
||||
onClose?.();
|
||||
}
|
||||
onFileUploadClose?.();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -152,20 +124,7 @@ export const useOpenFilesFieldInput = () => {
|
||||
null,
|
||||
);
|
||||
|
||||
if (isTableContext && isDefined(recordTableId)) {
|
||||
store.set(
|
||||
recordTableCellEditModePositionComponentState.atomFamily({
|
||||
instanceId: recordTableId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
goBackToPreviousDropdownFocusId();
|
||||
removeLastFocusItemFromFocusStackByComponentType({
|
||||
componentType: FocusComponentType.OPENED_FIELD_INPUT,
|
||||
});
|
||||
} else {
|
||||
onClose?.();
|
||||
}
|
||||
onFileUploadClose?.();
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
@@ -174,20 +133,7 @@ export const useOpenFilesFieldInput = () => {
|
||||
null,
|
||||
);
|
||||
|
||||
if (isTableContext && isDefined(recordTableId)) {
|
||||
store.set(
|
||||
recordTableCellEditModePositionComponentState.atomFamily({
|
||||
instanceId: recordTableId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
goBackToPreviousDropdownFocusId();
|
||||
removeLastFocusItemFromFocusStackByComponentType({
|
||||
componentType: FocusComponentType.OPENED_FIELD_INPUT,
|
||||
});
|
||||
} else {
|
||||
onClose?.();
|
||||
}
|
||||
onFileUploadClose?.();
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -195,9 +141,6 @@ export const useOpenFilesFieldInput = () => {
|
||||
openFileUpload,
|
||||
uploadFile,
|
||||
pushFocusItemToFocusStack,
|
||||
recordTableId,
|
||||
goBackToPreviousDropdownFocusId,
|
||||
removeLastFocusItemFromFocusStackByComponentType,
|
||||
enqueueErrorSnackBar,
|
||||
t,
|
||||
store,
|
||||
|
||||
+18
@@ -24,6 +24,9 @@ import { useFocusedRecordTableRow } from '@/object-record/record-table/hooks/use
|
||||
import { useFocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell';
|
||||
import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState';
|
||||
import { clickOutsideListenerIsActivatedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState';
|
||||
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
||||
import { useRemoveLastFocusItemFromFocusStackByComponentType } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackByComponentType';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
@@ -61,6 +64,12 @@ export const useOpenRecordTableCell = (recordTableId: string) => {
|
||||
|
||||
const { openFieldInput } = useOpenFieldInputEditMode();
|
||||
|
||||
const { goBackToPreviousDropdownFocusId } =
|
||||
useGoBackToPreviousDropdownFocusId();
|
||||
|
||||
const { removeLastFocusItemFromFocusStackByComponentType } =
|
||||
useRemoveLastFocusItemFromFocusStackByComponentType();
|
||||
|
||||
const { activateRecordTableRow, deactivateRecordTableRow } =
|
||||
useActiveRecordTableRow(recordTableId);
|
||||
|
||||
@@ -137,6 +146,13 @@ export const useOpenRecordTableCell = (recordTableId: string) => {
|
||||
fieldDefinition,
|
||||
recordId,
|
||||
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||
onFileUploadClose: () => {
|
||||
setRecordTableCellEditModePosition(null);
|
||||
goBackToPreviousDropdownFocusId();
|
||||
removeLastFocusItemFromFocusStackByComponentType({
|
||||
componentType: FocusComponentType.OPENED_FIELD_INPUT,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
setRecordTableCellEditModePosition(cellPosition);
|
||||
@@ -170,6 +186,8 @@ export const useOpenRecordTableCell = (recordTableId: string) => {
|
||||
setDragSelectionStartEnabled,
|
||||
openFieldInput,
|
||||
setRecordTableCellEditModePosition,
|
||||
goBackToPreviousDropdownFocusId,
|
||||
removeLastFocusItemFromFocusStackByComponentType,
|
||||
initDraftValue,
|
||||
toggleClickOutside,
|
||||
setActiveDropdownFocusIdAndMemorizePrevious,
|
||||
|
||||
@@ -58,6 +58,7 @@ const StyledContainer = styled.div`
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
height: ${TAB_LIST_HEIGHT};
|
||||
padding-left: ${themeCssVariables.spacing[2]};
|
||||
position: relative;
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
|
||||
+19
-26
@@ -28,7 +28,6 @@ import { styled } from '@linaria/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { SidePanelPages } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { useIsMobile } from 'twenty-ui/utilities';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
@@ -47,10 +46,6 @@ const StyledTabsAndDashboardContainer = styled.div`
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledPageLayoutTabListContainer = styled.div`
|
||||
padding-left: ${themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
const StyledScrollWrapperContainer = styled.div`
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
@@ -168,27 +163,25 @@ export const PageLayoutTabsRenderer = () => {
|
||||
}
|
||||
/>
|
||||
{(sortedTabs.length > 1 || isPageLayoutInEditMode) && (
|
||||
<StyledPageLayoutTabListContainer>
|
||||
<PageLayoutTabList
|
||||
tabs={sortedTabs}
|
||||
behaveAsLinks={!isInSidePanel && !isPageLayoutInEditMode}
|
||||
isInSidePanel={isInSidePanel}
|
||||
componentInstanceId={tabListInstanceId}
|
||||
onAddTab={handleAddTab}
|
||||
isReorderEnabled={canEnableTabEditing}
|
||||
onReorder={
|
||||
canEnableTabEditing
|
||||
? (result, provided) =>
|
||||
reorderRecordPageTabs(
|
||||
result,
|
||||
provided,
|
||||
isDefined(pinnedLeftTab),
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
pageLayoutType={currentPageLayout.type}
|
||||
/>
|
||||
</StyledPageLayoutTabListContainer>
|
||||
<PageLayoutTabList
|
||||
tabs={sortedTabs}
|
||||
behaveAsLinks={!isInSidePanel && !isPageLayoutInEditMode}
|
||||
isInSidePanel={isInSidePanel}
|
||||
componentInstanceId={tabListInstanceId}
|
||||
onAddTab={handleAddTab}
|
||||
isReorderEnabled={canEnableTabEditing}
|
||||
onReorder={
|
||||
canEnableTabEditing
|
||||
? (result, provided) =>
|
||||
reorderRecordPageTabs(
|
||||
result,
|
||||
provided,
|
||||
isDefined(pinnedLeftTab),
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
pageLayoutType={currentPageLayout.type}
|
||||
/>
|
||||
)}
|
||||
|
||||
<StyledScrollWrapperContainer>
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ export const PageLayoutVerticalListEditor = ({
|
||||
<StyledVerticalListContainer
|
||||
ref={provided.innerRef}
|
||||
variant={variant}
|
||||
shouldUseWhiteBackground={isMobile || isInSidePanel}
|
||||
shouldUseWhiteBackground={!isInPinnedTab || isMobile}
|
||||
// oxlint-disable-next-line react/jsx-props-no-spreading
|
||||
{...provided.droppableProps}
|
||||
>
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ export const PageLayoutVerticalListViewer = ({
|
||||
return (
|
||||
<StyledVerticalListContainer
|
||||
variant={variant}
|
||||
shouldUseWhiteBackground={isMobile || isInSidePanel}
|
||||
shouldUseWhiteBackground={!isInPinnedTab || isMobile}
|
||||
>
|
||||
{widgets.map((widget) => (
|
||||
<div key={widget.id}>
|
||||
|
||||
+5
@@ -64,6 +64,7 @@ const mixedGraphsPageLayoutMocks = {
|
||||
tabs: [
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
id: 'mixed-tab',
|
||||
title: 'Mixed Graphs',
|
||||
position: 0,
|
||||
@@ -74,6 +75,7 @@ const mixedGraphsPageLayoutMocks = {
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'number-widget',
|
||||
pageLayoutTabId: 'mixed-tab',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -98,6 +100,7 @@ const mixedGraphsPageLayoutMocks = {
|
||||
} satisfies PageLayoutWidget,
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'gauge-widget',
|
||||
pageLayoutTabId: 'mixed-tab',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -123,6 +126,7 @@ const mixedGraphsPageLayoutMocks = {
|
||||
} satisfies PageLayoutWidget,
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'pie-widget',
|
||||
pageLayoutTabId: 'mixed-tab',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -149,6 +153,7 @@ const mixedGraphsPageLayoutMocks = {
|
||||
} satisfies PageLayoutWidget,
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'bar-widget',
|
||||
pageLayoutTabId: 'mixed-tab',
|
||||
type: WidgetType.GRAPH,
|
||||
|
||||
+4
@@ -23,6 +23,7 @@ const StyledContainer = styled.div`
|
||||
const createInitialTabs = (): PageLayoutTab[] => [
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: 'overview',
|
||||
title: 'Overview',
|
||||
@@ -36,6 +37,7 @@ const createInitialTabs = (): PageLayoutTab[] => [
|
||||
},
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: 'revenue',
|
||||
title: 'Revenue',
|
||||
@@ -48,6 +50,7 @@ const createInitialTabs = (): PageLayoutTab[] => [
|
||||
},
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: 'forecasts',
|
||||
title: 'Forecasts',
|
||||
@@ -77,6 +80,7 @@ const PageLayoutTabListPlayground = ({
|
||||
...prev,
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: `new-tab-${nextIndex}`,
|
||||
title: `New Tab ${nextIndex}`,
|
||||
|
||||
+14
@@ -21,6 +21,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'company-tab-fields',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
icon: 'IconHome',
|
||||
position: 100,
|
||||
@@ -33,6 +34,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'company-widget-fields',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'company-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -59,6 +61,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'company-tab-timeline',
|
||||
isActive: true,
|
||||
title: 'Timeline',
|
||||
icon: 'IconTimelineEvent',
|
||||
position: 200,
|
||||
@@ -71,6 +74,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'company-widget-timeline',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'company-tab-timeline',
|
||||
title: 'Timeline',
|
||||
type: WidgetType.TIMELINE,
|
||||
@@ -97,6 +101,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'company-tab-tasks',
|
||||
isActive: true,
|
||||
title: 'Tasks',
|
||||
icon: 'IconCheckbox',
|
||||
position: 300,
|
||||
@@ -109,6 +114,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'company-widget-tasks',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'company-tab-tasks',
|
||||
title: 'Tasks',
|
||||
type: WidgetType.TASKS,
|
||||
@@ -135,6 +141,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'company-tab-notes',
|
||||
isActive: true,
|
||||
title: 'Notes',
|
||||
icon: 'IconNotes',
|
||||
position: 400,
|
||||
@@ -147,6 +154,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'company-widget-notes',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'company-tab-notes',
|
||||
title: 'Notes',
|
||||
type: WidgetType.NOTES,
|
||||
@@ -173,6 +181,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'company-tab-files',
|
||||
isActive: true,
|
||||
title: 'Files',
|
||||
icon: 'IconPaperclip',
|
||||
position: 500,
|
||||
@@ -185,6 +194,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'company-widget-files',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'company-tab-files',
|
||||
title: 'Files',
|
||||
type: WidgetType.FILES,
|
||||
@@ -211,6 +221,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'company-tab-emails',
|
||||
isActive: true,
|
||||
title: 'Emails',
|
||||
icon: 'IconMail',
|
||||
position: 600,
|
||||
@@ -223,6 +234,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'company-widget-emails',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'company-tab-emails',
|
||||
title: 'Emails',
|
||||
type: WidgetType.EMAILS,
|
||||
@@ -249,6 +261,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'company-tab-calendar',
|
||||
isActive: true,
|
||||
title: 'Calendar',
|
||||
icon: 'IconCalendarEvent',
|
||||
position: 700,
|
||||
@@ -261,6 +274,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'company-widget-calendar',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'company-tab-calendar',
|
||||
title: 'Calendar',
|
||||
type: WidgetType.CALENDAR,
|
||||
|
||||
+2
@@ -21,6 +21,7 @@ export const DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'message-thread-tab-home',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
icon: 'IconHome',
|
||||
position: 100,
|
||||
@@ -33,6 +34,7 @@ export const DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'message-thread-widget-email-thread',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'message-thread-tab-home',
|
||||
title: 'Thread',
|
||||
type: WidgetType.EMAIL_THREAD,
|
||||
|
||||
@@ -21,6 +21,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'note-tab-fields',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
icon: 'IconHome',
|
||||
position: 100,
|
||||
@@ -33,6 +34,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'note-widget-fields',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'note-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -59,6 +61,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'note-widget-note',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'note-tab-fields',
|
||||
title: 'Note',
|
||||
type: WidgetType.FIELD_RICH_TEXT,
|
||||
@@ -92,6 +95,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'note-tab-note',
|
||||
isActive: true,
|
||||
title: 'Note',
|
||||
icon: 'IconNotes',
|
||||
position: 150,
|
||||
@@ -104,6 +108,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'note-widget-note',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'note-tab-note',
|
||||
title: 'Note',
|
||||
type: WidgetType.FIELD_RICH_TEXT,
|
||||
@@ -137,6 +142,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'note-tab-timeline',
|
||||
isActive: true,
|
||||
title: 'Timeline',
|
||||
icon: 'IconTimelineEvent',
|
||||
position: 200,
|
||||
@@ -149,6 +155,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'note-widget-timeline',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'note-tab-timeline',
|
||||
title: 'Timeline',
|
||||
type: WidgetType.TIMELINE,
|
||||
@@ -175,6 +182,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'note-tab-files',
|
||||
isActive: true,
|
||||
title: 'Files',
|
||||
icon: 'IconPaperclip',
|
||||
position: 300,
|
||||
@@ -187,6 +195,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'note-widget-files',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'note-tab-files',
|
||||
title: 'Files',
|
||||
type: WidgetType.FILES,
|
||||
|
||||
+14
@@ -21,6 +21,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'opportunity-tab-fields',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
icon: 'IconHome',
|
||||
position: 100,
|
||||
@@ -33,6 +34,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'opportunity-widget-fields',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'opportunity-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -59,6 +61,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'opportunity-tab-timeline',
|
||||
isActive: true,
|
||||
title: 'Timeline',
|
||||
icon: 'IconTimelineEvent',
|
||||
position: 200,
|
||||
@@ -71,6 +74,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'opportunity-widget-timeline',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'opportunity-tab-timeline',
|
||||
title: 'Timeline',
|
||||
type: WidgetType.TIMELINE,
|
||||
@@ -97,6 +101,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'opportunity-tab-tasks',
|
||||
isActive: true,
|
||||
title: 'Tasks',
|
||||
icon: 'IconCheckbox',
|
||||
position: 300,
|
||||
@@ -109,6 +114,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'opportunity-widget-tasks',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'opportunity-tab-tasks',
|
||||
title: 'Tasks',
|
||||
type: WidgetType.TASKS,
|
||||
@@ -135,6 +141,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'opportunity-tab-notes',
|
||||
isActive: true,
|
||||
title: 'Notes',
|
||||
icon: 'IconNotes',
|
||||
position: 400,
|
||||
@@ -147,6 +154,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'opportunity-widget-notes',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'opportunity-tab-notes',
|
||||
title: 'Notes',
|
||||
type: WidgetType.NOTES,
|
||||
@@ -173,6 +181,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'opportunity-tab-files',
|
||||
isActive: true,
|
||||
title: 'Files',
|
||||
icon: 'IconPaperclip',
|
||||
position: 500,
|
||||
@@ -185,6 +194,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'opportunity-widget-files',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'opportunity-tab-files',
|
||||
title: 'Files',
|
||||
type: WidgetType.FILES,
|
||||
@@ -211,6 +221,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'opportunity-tab-emails',
|
||||
isActive: true,
|
||||
title: 'Emails',
|
||||
icon: 'IconMail',
|
||||
position: 600,
|
||||
@@ -223,6 +234,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'opportunity-widget-emails',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'opportunity-tab-emails',
|
||||
title: 'Emails',
|
||||
type: WidgetType.EMAILS,
|
||||
@@ -249,6 +261,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'opportunity-tab-calendar',
|
||||
isActive: true,
|
||||
title: 'Calendar',
|
||||
icon: 'IconCalendarEvent',
|
||||
position: 700,
|
||||
@@ -261,6 +274,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'opportunity-widget-calendar',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'opportunity-tab-calendar',
|
||||
title: 'Calendar',
|
||||
type: WidgetType.CALENDAR,
|
||||
|
||||
+14
@@ -21,6 +21,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'person-tab-fields',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
icon: 'IconHome',
|
||||
position: 100,
|
||||
@@ -33,6 +34,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'person-widget-fields',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'person-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -59,6 +61,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'person-tab-timeline',
|
||||
isActive: true,
|
||||
title: 'Timeline',
|
||||
icon: 'IconTimelineEvent',
|
||||
position: 200,
|
||||
@@ -71,6 +74,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'person-widget-timeline',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'person-tab-timeline',
|
||||
title: 'Timeline',
|
||||
type: WidgetType.TIMELINE,
|
||||
@@ -97,6 +101,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'person-tab-tasks',
|
||||
isActive: true,
|
||||
title: 'Tasks',
|
||||
icon: 'IconCheckbox',
|
||||
position: 300,
|
||||
@@ -109,6 +114,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'person-widget-tasks',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'person-tab-tasks',
|
||||
title: 'Tasks',
|
||||
type: WidgetType.TASKS,
|
||||
@@ -135,6 +141,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'person-tab-notes',
|
||||
isActive: true,
|
||||
title: 'Notes',
|
||||
icon: 'IconNotes',
|
||||
position: 400,
|
||||
@@ -147,6 +154,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'person-widget-notes',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'person-tab-notes',
|
||||
title: 'Notes',
|
||||
type: WidgetType.NOTES,
|
||||
@@ -173,6 +181,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'person-tab-files',
|
||||
isActive: true,
|
||||
title: 'Files',
|
||||
icon: 'IconPaperclip',
|
||||
position: 500,
|
||||
@@ -185,6 +194,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'person-widget-files',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'person-tab-files',
|
||||
title: 'Files',
|
||||
type: WidgetType.FILES,
|
||||
@@ -211,6 +221,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'person-tab-emails',
|
||||
isActive: true,
|
||||
title: 'Emails',
|
||||
icon: 'IconMail',
|
||||
position: 600,
|
||||
@@ -223,6 +234,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'person-widget-emails',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'person-tab-emails',
|
||||
title: 'Emails',
|
||||
type: WidgetType.EMAILS,
|
||||
@@ -249,6 +261,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'person-tab-calendar',
|
||||
isActive: true,
|
||||
title: 'Calendar',
|
||||
icon: 'IconCalendarEvent',
|
||||
position: 700,
|
||||
@@ -261,6 +274,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'person-widget-calendar',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'person-tab-calendar',
|
||||
title: 'Calendar',
|
||||
type: WidgetType.CALENDAR,
|
||||
|
||||
@@ -21,6 +21,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'default-tab-fields',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
icon: 'IconHome',
|
||||
position: 100,
|
||||
@@ -33,6 +34,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-fields',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'default-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -59,6 +61,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'default-tab-timeline',
|
||||
isActive: true,
|
||||
title: 'Timeline',
|
||||
icon: 'IconTimelineEvent',
|
||||
position: 200,
|
||||
@@ -71,6 +74,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-timeline',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'default-tab-timeline',
|
||||
title: 'Timeline',
|
||||
type: WidgetType.TIMELINE,
|
||||
@@ -97,6 +101,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'default-tab-tasks',
|
||||
isActive: true,
|
||||
title: 'Tasks',
|
||||
icon: 'IconCheckbox',
|
||||
position: 300,
|
||||
@@ -109,6 +114,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-tasks',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'default-tab-tasks',
|
||||
title: 'Tasks',
|
||||
type: WidgetType.TASKS,
|
||||
@@ -135,6 +141,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'default-tab-notes',
|
||||
isActive: true,
|
||||
title: 'Notes',
|
||||
icon: 'IconNotes',
|
||||
position: 400,
|
||||
@@ -147,6 +154,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-notes',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'default-tab-notes',
|
||||
title: 'Notes',
|
||||
type: WidgetType.NOTES,
|
||||
@@ -173,6 +181,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'default-tab-files',
|
||||
isActive: true,
|
||||
title: 'Files',
|
||||
icon: 'IconPaperclip',
|
||||
position: 500,
|
||||
@@ -185,6 +194,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-files',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'default-tab-files',
|
||||
title: 'Files',
|
||||
type: WidgetType.FILES,
|
||||
|
||||
@@ -21,6 +21,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'task-tab-fields',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
icon: 'IconHome',
|
||||
position: 100,
|
||||
@@ -33,6 +34,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'task-widget-fields',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'task-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -56,6 +58,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'task-widget-note',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'task-tab-fields',
|
||||
title: 'Note',
|
||||
type: WidgetType.FIELD_RICH_TEXT,
|
||||
@@ -89,6 +92,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'task-tab-note',
|
||||
isActive: true,
|
||||
title: 'Note',
|
||||
icon: 'IconNotes',
|
||||
position: 150,
|
||||
@@ -101,6 +105,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'task-widget-note',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'task-tab-note',
|
||||
title: 'Note',
|
||||
type: WidgetType.FIELD_RICH_TEXT,
|
||||
@@ -134,6 +139,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'task-tab-timeline',
|
||||
isActive: true,
|
||||
title: 'Timeline',
|
||||
icon: 'IconTimelineEvent',
|
||||
position: 200,
|
||||
@@ -146,6 +152,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'task-widget-timeline',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'task-tab-timeline',
|
||||
title: 'Timeline',
|
||||
type: WidgetType.TIMELINE,
|
||||
@@ -172,6 +179,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'task-tab-files',
|
||||
isActive: true,
|
||||
title: 'Files',
|
||||
icon: 'IconPaperclip',
|
||||
position: 300,
|
||||
@@ -184,6 +192,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'task-widget-files',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'task-tab-files',
|
||||
title: 'Files',
|
||||
type: WidgetType.FILES,
|
||||
|
||||
@@ -26,6 +26,7 @@ export const DEFAULT_WORKFLOW_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'workflow-tab-flow',
|
||||
isActive: true,
|
||||
title: 'Flow',
|
||||
position: 100,
|
||||
layoutMode: PageLayoutTabLayoutMode.CANVAS,
|
||||
@@ -38,6 +39,7 @@ export const DEFAULT_WORKFLOW_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'workflow-widget-flow',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'workflow-tab-flow',
|
||||
title: 'Flow',
|
||||
type: WidgetType.WORKFLOW,
|
||||
|
||||
+4
@@ -27,6 +27,7 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'workflow-run-tab-fields',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
position: 100,
|
||||
layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
|
||||
@@ -39,6 +40,7 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'workflow-run-widget-fields',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'workflow-run-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -66,6 +68,7 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'workflow-run-tab-flow',
|
||||
isActive: true,
|
||||
title: 'Flow',
|
||||
position: 200,
|
||||
layoutMode: PageLayoutTabLayoutMode.CANVAS,
|
||||
@@ -78,6 +81,7 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'workflow-run-widget-flow',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'workflow-run-tab-flow',
|
||||
title: 'Flow',
|
||||
type: WidgetType.WORKFLOW_RUN,
|
||||
|
||||
+4
@@ -27,6 +27,7 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'workflow-version-tab-fields',
|
||||
isActive: true,
|
||||
title: 'Home',
|
||||
icon: 'IconHome',
|
||||
position: 100,
|
||||
@@ -39,6 +40,7 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'workflow-version-widget-fields',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'workflow-version-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -66,6 +68,7 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id: 'workflow-version-tab-flow',
|
||||
isActive: true,
|
||||
title: 'Flow',
|
||||
icon: 'IconSettings',
|
||||
position: 200,
|
||||
@@ -78,6 +81,7 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'workflow-version-widget-flow',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'workflow-version-tab-flow',
|
||||
title: 'Flow',
|
||||
type: WidgetType.WORKFLOW_VERSION,
|
||||
|
||||
+1
@@ -8,6 +8,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
|
||||
objectMetadataId
|
||||
createdAt
|
||||
updatedAt
|
||||
isActive
|
||||
deletedAt
|
||||
conditionalDisplay
|
||||
conditionalAvailabilityExpression
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ const makeWidget = (
|
||||
id,
|
||||
pageLayoutTabId: tabId,
|
||||
title: id,
|
||||
isActive: true,
|
||||
type: WidgetType.FIELDS,
|
||||
gridPosition: { column: 0, columnSpan: 1, row: 0, rowSpan: 1 },
|
||||
configuration: { __typename: 'FieldsConfiguration' as const },
|
||||
@@ -46,6 +47,7 @@ const makeTab = (
|
||||
id,
|
||||
applicationId: '',
|
||||
title: id,
|
||||
isActive: true,
|
||||
position,
|
||||
layoutMode,
|
||||
pageLayoutId: '',
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ const makeWidget = (
|
||||
id,
|
||||
pageLayoutTabId: tabId,
|
||||
title: id,
|
||||
isActive: true,
|
||||
type: WidgetType.FIELDS,
|
||||
gridPosition: { column: 0, columnSpan: 1, row: 0, rowSpan: 1 },
|
||||
configuration: { __typename: 'FieldsConfiguration' as const },
|
||||
@@ -46,6 +47,7 @@ const makeTab = (
|
||||
id,
|
||||
applicationId: '',
|
||||
title: id,
|
||||
isActive: true,
|
||||
position,
|
||||
layoutMode,
|
||||
pageLayoutId: '',
|
||||
|
||||
+2
@@ -79,6 +79,7 @@ describe('useCreatePageLayoutGraphWidget', () => {
|
||||
id: 'tab-1',
|
||||
applicationId: '',
|
||||
title: 'Tab 1',
|
||||
isActive: true,
|
||||
position: 0,
|
||||
pageLayoutId: '',
|
||||
widgets: [],
|
||||
@@ -162,6 +163,7 @@ describe('useCreatePageLayoutGraphWidget', () => {
|
||||
id: 'tab-1',
|
||||
applicationId: '',
|
||||
title: 'Tab 1',
|
||||
isActive: true,
|
||||
position: 0,
|
||||
pageLayoutId: '',
|
||||
widgets: [],
|
||||
|
||||
+1
@@ -308,6 +308,7 @@ describe('useCreatePageLayoutTab', () => {
|
||||
id: 'existing-tab',
|
||||
applicationId: '',
|
||||
title: 'Existing Tab',
|
||||
isActive: true,
|
||||
position: 0,
|
||||
pageLayoutId: 'test-layout',
|
||||
widgets: [],
|
||||
|
||||
+2
@@ -25,6 +25,7 @@ const makeWidget = (
|
||||
id,
|
||||
pageLayoutTabId: tabId,
|
||||
title: id,
|
||||
isActive: true,
|
||||
type: WidgetType.FIELDS,
|
||||
gridPosition: { column: 0, columnSpan: 1, row: 0, rowSpan: 1 },
|
||||
configuration: { __typename: 'FieldsConfiguration' as const },
|
||||
@@ -46,6 +47,7 @@ const makeTab = (
|
||||
id,
|
||||
applicationId: '',
|
||||
title: id,
|
||||
isActive: true,
|
||||
position,
|
||||
pageLayoutId: '',
|
||||
widgets,
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ const makeWidget = (
|
||||
id,
|
||||
pageLayoutTabId: tabId,
|
||||
title: id,
|
||||
isActive: true,
|
||||
type: WidgetType.FIELDS,
|
||||
gridPosition: { column: 0, columnSpan: 1, row: 0, rowSpan: 1 },
|
||||
configuration: { __typename: 'FieldsConfiguration' as const },
|
||||
@@ -45,6 +46,7 @@ const makeTab = (
|
||||
id,
|
||||
applicationId: '',
|
||||
title: id,
|
||||
isActive: true,
|
||||
position,
|
||||
layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
|
||||
pageLayoutId: '',
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ const makeWidget = (
|
||||
id,
|
||||
pageLayoutTabId: tabId,
|
||||
title: id,
|
||||
isActive: true,
|
||||
type: WidgetType.FIELDS,
|
||||
gridPosition: { column: 0, columnSpan: 1, row: 0, rowSpan: 1 },
|
||||
configuration: { __typename: 'FieldsConfiguration' as const },
|
||||
@@ -45,6 +46,7 @@ const makeTab = (
|
||||
id,
|
||||
applicationId: '',
|
||||
title: id,
|
||||
isActive: true,
|
||||
position,
|
||||
layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
|
||||
pageLayoutId: '',
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ const makeWidget = (
|
||||
id,
|
||||
pageLayoutTabId: tabId,
|
||||
title: id,
|
||||
isActive: true,
|
||||
type: WidgetType.FIELDS,
|
||||
gridPosition: { column: 0, columnSpan: 1, row: 0, rowSpan: 1 },
|
||||
configuration: { __typename: 'FieldsConfiguration' as const },
|
||||
@@ -45,6 +46,7 @@ const makeTab = (
|
||||
id,
|
||||
applicationId: '',
|
||||
title: id,
|
||||
isActive: true,
|
||||
position,
|
||||
layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
|
||||
pageLayoutId: '',
|
||||
|
||||
+2
@@ -90,6 +90,7 @@ describe('usePageLayoutDraftState', () => {
|
||||
id: 'tab-1',
|
||||
applicationId: '',
|
||||
title: 'Tab 1',
|
||||
isActive: true,
|
||||
position: 0,
|
||||
pageLayoutId: '',
|
||||
createdAt: new Date().toISOString(),
|
||||
@@ -100,6 +101,7 @@ describe('usePageLayoutDraftState', () => {
|
||||
id: 'widget-1',
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'New Widget',
|
||||
isActive: true,
|
||||
type: WidgetType.GRAPH,
|
||||
gridPosition: { row: 2, column: 2, rowSpan: 2, columnSpan: 2 },
|
||||
configuration: {
|
||||
|
||||
+5
@@ -35,6 +35,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
|
||||
applicationId: '',
|
||||
id: 'tab-1',
|
||||
title: 'Fields',
|
||||
isActive: true,
|
||||
icon: 'IconList',
|
||||
position: 100,
|
||||
layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
|
||||
@@ -48,6 +49,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
|
||||
id: 'widget-fields',
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Fields',
|
||||
isActive: true,
|
||||
type: WidgetType.FIELDS,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
@@ -71,6 +73,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
|
||||
id: 'widget-notes',
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Notes',
|
||||
isActive: true,
|
||||
type: WidgetType.NOTES,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
@@ -93,6 +96,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
|
||||
id: 'widget-other',
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Other',
|
||||
isActive: true,
|
||||
type: WidgetType.GRAPH,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
@@ -217,6 +221,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
|
||||
id: 'widget-other',
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Other',
|
||||
isActive: true,
|
||||
type: WidgetType.GRAPH,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
|
||||
@@ -54,6 +54,7 @@ export const useCreatePageLayoutTab = ({
|
||||
const newTab: PageLayoutTab = {
|
||||
id: newTabId,
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
title: title || `Tab ${tabsLength + 1}`,
|
||||
position: maxPosition + 1,
|
||||
pageLayoutId: pageLayoutId,
|
||||
|
||||
-1
@@ -39,7 +39,6 @@ export const useCreatePendingFieldsWidgetViews = () => {
|
||||
if (widget.type !== WidgetType.FIELDS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const viewId = getWidgetConfigurationViewId(widget.configuration);
|
||||
|
||||
return isDefined(viewId) && !persistedWidgetIds.has(widget.id);
|
||||
|
||||
@@ -2,18 +2,14 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/context
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
|
||||
import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
|
||||
import { removeWidgetFromTab } from '@/page-layout/utils/removeWidgetFromTab';
|
||||
import { removeWidgetLayoutFromTab } from '@/page-layout/utils/removeWidgetLayoutFromTab';
|
||||
import { useDeleteViewForFieldsWidget } from '@/page-layout/widgets/fields/hooks/useDeleteViewForFieldsWidget';
|
||||
import { useDeleteViewForRecordTableWidget } from '@/page-layout/widgets/record-table/hooks/useDeleteViewForRecordTableWidget';
|
||||
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { WidgetType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useDeletePageLayoutWidget = (pageLayoutIdFromProps?: string) => {
|
||||
const pageLayoutId = useAvailableComponentInstanceIdOrThrow(
|
||||
@@ -38,16 +34,6 @@ export const useDeletePageLayoutWidget = (pageLayoutIdFromProps?: string) => {
|
||||
|
||||
const { closeSidePanelMenu } = useSidePanelMenu();
|
||||
|
||||
const { deleteViewForFieldsWidget } = useDeleteViewForFieldsWidget();
|
||||
|
||||
const { deleteViewForRecordTableWidget } =
|
||||
useDeleteViewForRecordTableWidget();
|
||||
|
||||
const pageLayoutPersistedState = useAtomComponentStateCallbackState(
|
||||
pageLayoutPersistedComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const deletePageLayoutWidget = useCallback(
|
||||
@@ -61,43 +47,6 @@ export const useDeletePageLayoutWidget = (pageLayoutIdFromProps?: string) => {
|
||||
tab.widgets.some((widget) => widget.id === widgetId),
|
||||
);
|
||||
|
||||
const widgetToDelete = tabWithWidget?.widgets.find(
|
||||
(widget) => widget.id === widgetId,
|
||||
);
|
||||
|
||||
const persisted = store.get(pageLayoutPersistedState);
|
||||
const persistedWidgetIds = new Set(
|
||||
persisted?.tabs.flatMap((tab) =>
|
||||
tab.widgets.map((widget) => widget.id),
|
||||
) ?? [],
|
||||
);
|
||||
|
||||
const isWidgetPersisted = persistedWidgetIds.has(widgetId);
|
||||
|
||||
if (
|
||||
isWidgetPersisted &&
|
||||
isDefined(widgetToDelete) &&
|
||||
widgetToDelete.type === WidgetType.RECORD_TABLE &&
|
||||
'viewId' in widgetToDelete.configuration &&
|
||||
isDefined(widgetToDelete.configuration.viewId)
|
||||
) {
|
||||
deleteViewForRecordTableWidget(
|
||||
widgetToDelete.configuration.viewId as string,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
isWidgetPersisted &&
|
||||
isDefined(widgetToDelete) &&
|
||||
widgetToDelete.type === WidgetType.FIELDS &&
|
||||
'viewId' in widgetToDelete.configuration &&
|
||||
isDefined(widgetToDelete.configuration.viewId)
|
||||
) {
|
||||
deleteViewForFieldsWidget(
|
||||
widgetToDelete.configuration.viewId as string,
|
||||
);
|
||||
}
|
||||
|
||||
const tabId = tabWithWidget?.id;
|
||||
|
||||
if (isDefined(tabId)) {
|
||||
@@ -124,12 +73,9 @@ export const useDeletePageLayoutWidget = (pageLayoutIdFromProps?: string) => {
|
||||
},
|
||||
[
|
||||
closeSidePanelMenu,
|
||||
deleteViewForFieldsWidget,
|
||||
deleteViewForRecordTableWidget,
|
||||
pageLayoutCurrentLayoutsState,
|
||||
pageLayoutDraftState,
|
||||
pageLayoutEditingWidgetIdState,
|
||||
pageLayoutPersistedState,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
+5
-3
@@ -27,20 +27,22 @@ export const usePageLayoutTabWithVisibleWidgetsOrThrow = (
|
||||
throw new Error('Tab not found');
|
||||
}
|
||||
|
||||
const activeWidgets = tab.widgets.filter((widget) => widget.isActive);
|
||||
|
||||
if (isPageLayoutInEditMode) {
|
||||
return {
|
||||
...tab,
|
||||
widgets:
|
||||
tab.layoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST
|
||||
? sortWidgetsByVerticalListPosition(tab.widgets)
|
||||
: tab.widgets,
|
||||
? sortWidgetsByVerticalListPosition(activeWidgets)
|
||||
: activeWidgets,
|
||||
};
|
||||
}
|
||||
|
||||
const context = buildWidgetVisibilityContext({ isMobile, isInSidePanel });
|
||||
|
||||
const visibleWidgets = filterVisibleWidgets({
|
||||
widgets: tab.widgets,
|
||||
widgets: activeWidgets,
|
||||
context,
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ import { useExitLayoutCustomizationMode } from '@/layout-customization/hooks/use
|
||||
import { useInvalidateMetadataStore } from '@/metadata-store/hooks/useInvalidateMetadataStore';
|
||||
import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode';
|
||||
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
|
||||
import { fieldsWidgetEditorModeDraftComponentState } from '@/page-layout/states/fieldsWidgetEditorModeDraftComponentState';
|
||||
import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState';
|
||||
import { fieldsWidgetUngroupedFieldsDraftComponentState } from '@/page-layout/states/fieldsWidgetUngroupedFieldsDraftComponentState';
|
||||
import { hasInitializedFieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
|
||||
@@ -50,6 +54,28 @@ export const useRefreshPageLayoutAfterReset = (
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const fieldsWidgetGroupsDraftState = useAtomComponentStateCallbackState(
|
||||
fieldsWidgetGroupsDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const fieldsWidgetUngroupedFieldsDraftState =
|
||||
useAtomComponentStateCallbackState(
|
||||
fieldsWidgetUngroupedFieldsDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const fieldsWidgetEditorModeDraftState = useAtomComponentStateCallbackState(
|
||||
fieldsWidgetEditorModeDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const hasInitializedFieldsWidgetGroupsDraftState =
|
||||
useAtomComponentStateCallbackState(
|
||||
hasInitializedFieldsWidgetGroupsDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const refreshPageLayoutAfterReset = useCallback(
|
||||
async (collectAffectedViewIds: (layout: PageLayout) => Set<string>) => {
|
||||
const { data } = await client.query({
|
||||
@@ -73,6 +99,11 @@ export const useRefreshPageLayoutAfterReset = (
|
||||
);
|
||||
}
|
||||
|
||||
store.set(fieldsWidgetGroupsDraftState, {});
|
||||
store.set(fieldsWidgetUngroupedFieldsDraftState, {});
|
||||
store.set(fieldsWidgetEditorModeDraftState, {});
|
||||
store.set(hasInitializedFieldsWidgetGroupsDraftState, {});
|
||||
|
||||
setIsPageLayoutInEditMode(false);
|
||||
exitLayoutCustomizationMode();
|
||||
evictViewMetadataForViewIds(store, affectedViewIds);
|
||||
@@ -85,6 +116,10 @@ export const useRefreshPageLayoutAfterReset = (
|
||||
pageLayoutPersistedState,
|
||||
pageLayoutDraftState,
|
||||
pageLayoutCurrentLayoutsState,
|
||||
fieldsWidgetGroupsDraftState,
|
||||
fieldsWidgetUngroupedFieldsDraftState,
|
||||
fieldsWidgetEditorModeDraftState,
|
||||
hasInitializedFieldsWidgetGroupsDraftState,
|
||||
setIsPageLayoutInEditMode,
|
||||
exitLayoutCustomizationMode,
|
||||
invalidateMetadataStore,
|
||||
|
||||
-47
@@ -3,18 +3,13 @@ import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pag
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutDraggedAreaComponentState } from '@/page-layout/states/pageLayoutDraggedAreaComponentState';
|
||||
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
|
||||
import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
|
||||
import { getWidgetConfigurationViewId } from '@/page-layout/utils/getWidgetConfigurationViewId';
|
||||
import { removeWidgetFromTab } from '@/page-layout/utils/removeWidgetFromTab';
|
||||
import { removeWidgetLayoutFromTab } from '@/page-layout/utils/removeWidgetLayoutFromTab';
|
||||
import { useDeleteViewForFieldsWidget } from '@/page-layout/widgets/fields/hooks/useDeleteViewForFieldsWidget';
|
||||
import { useDeleteViewForRecordTableWidget } from '@/page-layout/widgets/record-table/hooks/useDeleteViewForRecordTableWidget';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { WidgetType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useRemovePageLayoutWidgetAndPreservePosition = (
|
||||
pageLayoutIdFromProps?: string,
|
||||
@@ -44,16 +39,6 @@ export const useRemovePageLayoutWidgetAndPreservePosition = (
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const { deleteViewForFieldsWidget } = useDeleteViewForFieldsWidget();
|
||||
|
||||
const { deleteViewForRecordTableWidget } =
|
||||
useDeleteViewForRecordTableWidget();
|
||||
|
||||
const pageLayoutPersistedState = useAtomComponentStateCallbackState(
|
||||
pageLayoutPersistedComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const removePageLayoutWidgetAndPreservePosition = useCallback(
|
||||
@@ -65,35 +50,6 @@ export const useRemovePageLayoutWidgetAndPreservePosition = (
|
||||
tab.widgets.some((widget) => widget.id === widgetId),
|
||||
);
|
||||
|
||||
const widgetToRemove = tabWithWidget?.widgets.find(
|
||||
(widget) => widget.id === widgetId,
|
||||
);
|
||||
|
||||
const persisted = store.get(pageLayoutPersistedState);
|
||||
const persistedWidgetIds = new Set(
|
||||
persisted?.tabs.flatMap((tab) =>
|
||||
tab.widgets.map((widget) => widget.id),
|
||||
) ?? [],
|
||||
);
|
||||
|
||||
const isWidgetPersisted = persistedWidgetIds.has(widgetId);
|
||||
|
||||
if (isWidgetPersisted && isDefined(widgetToRemove)) {
|
||||
const viewId = getWidgetConfigurationViewId(
|
||||
widgetToRemove.configuration,
|
||||
);
|
||||
|
||||
if (isDefined(viewId)) {
|
||||
if (widgetToRemove.type === WidgetType.RECORD_TABLE) {
|
||||
deleteViewForRecordTableWidget(viewId);
|
||||
}
|
||||
|
||||
if (widgetToRemove.type === WidgetType.FIELDS) {
|
||||
deleteViewForFieldsWidget(viewId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tabId = tabWithWidget?.id;
|
||||
|
||||
if (!isDefined(tabId)) {
|
||||
@@ -131,13 +87,10 @@ export const useRemovePageLayoutWidgetAndPreservePosition = (
|
||||
store.set(pageLayoutEditingWidgetIdState, null);
|
||||
},
|
||||
[
|
||||
deleteViewForFieldsWidget,
|
||||
deleteViewForRecordTableWidget,
|
||||
pageLayoutCurrentLayoutsState,
|
||||
pageLayoutDraftState,
|
||||
pageLayoutDraggedAreaState,
|
||||
pageLayoutEditingWidgetIdState,
|
||||
pageLayoutPersistedState,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
+7
-2
@@ -18,10 +18,15 @@ export const pageLayoutsWithRelationsSelector = createAtomSelector<
|
||||
const allFlatWidgets = get(metadataStoreState, 'pageLayoutWidgets')
|
||||
.current as FlatPageLayoutWidget[];
|
||||
|
||||
const activeFlatTabs = allFlatTabs.filter((tab) => tab.isActive);
|
||||
const activeFlatWidgets = allFlatWidgets.filter(
|
||||
(widget) => widget.isActive,
|
||||
);
|
||||
|
||||
const tabsByPageLayoutId = new Map<string, FlatPageLayoutTab[]>();
|
||||
const widgetsByTabId = new Map<string, FlatPageLayoutWidget[]>();
|
||||
|
||||
for (const tab of allFlatTabs) {
|
||||
for (const tab of activeFlatTabs) {
|
||||
const existing = tabsByPageLayoutId.get(tab.pageLayoutId);
|
||||
|
||||
if (isDefined(existing)) {
|
||||
@@ -31,7 +36,7 @@ export const pageLayoutsWithRelationsSelector = createAtomSelector<
|
||||
}
|
||||
}
|
||||
|
||||
for (const widget of allFlatWidgets) {
|
||||
for (const widget of activeFlatWidgets) {
|
||||
const existing = widgetsByTabId.get(widget.pageLayoutTabId);
|
||||
|
||||
if (isDefined(existing)) {
|
||||
|
||||
@@ -11,6 +11,7 @@ describe('addWidgetToTab', () => {
|
||||
const mockWidget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'widget-1',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Test Widget',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -31,6 +32,7 @@ describe('addWidgetToTab', () => {
|
||||
{
|
||||
id: 'tab-1',
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
title: 'Tab 1',
|
||||
position: 0,
|
||||
pageLayoutId: 'layout-1',
|
||||
@@ -42,6 +44,7 @@ describe('addWidgetToTab', () => {
|
||||
{
|
||||
id: 'tab-2',
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
title: 'Tab 2',
|
||||
position: 1,
|
||||
pageLayoutId: 'layout-1',
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ describe('convertLayoutsToWidgets', () => {
|
||||
const mockWidgets: PageLayoutWidget[] = [
|
||||
{
|
||||
id: 'widget-1',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Widget 1',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -34,6 +35,7 @@ describe('convertLayoutsToWidgets', () => {
|
||||
},
|
||||
{
|
||||
id: 'widget-2',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Widget 2',
|
||||
type: WidgetType.GRAPH,
|
||||
|
||||
+5
@@ -20,6 +20,7 @@ describe('convertPageLayoutToTabLayouts', () => {
|
||||
{
|
||||
id: 'tab-1',
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
title: 'Tab 1',
|
||||
position: 0,
|
||||
pageLayoutId: 'page-layout-1',
|
||||
@@ -27,6 +28,7 @@ describe('convertPageLayoutToTabLayouts', () => {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'widget-1',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Widget 1',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -45,6 +47,7 @@ describe('convertPageLayoutToTabLayouts', () => {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'widget-2',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Widget 2',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -99,6 +102,7 @@ describe('convertPageLayoutToTabLayouts', () => {
|
||||
{
|
||||
id: 'tab-1',
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
title: 'Tab 1',
|
||||
position: 0,
|
||||
pageLayoutId: 'page-layout-1',
|
||||
@@ -106,6 +110,7 @@ describe('convertPageLayoutToTabLayouts', () => {
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'rich-text-widget',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Rich Text',
|
||||
type: WidgetType.STANDALONE_RICH_TEXT,
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ const createMockWidget = (
|
||||
},
|
||||
): PageLayoutWidget => ({
|
||||
id: 'widget-1',
|
||||
isActive: true,
|
||||
type: WidgetType.GRAPH,
|
||||
title: 'Test',
|
||||
objectMetadataId: null,
|
||||
|
||||
+1
@@ -12,6 +12,7 @@ describe('filterVisibleWidgets', () => {
|
||||
): PageLayoutTab['widgets'][0] => ({
|
||||
__typename: 'PageLayoutWidget',
|
||||
id,
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: `Widget ${id}`,
|
||||
type: WidgetType.FIELDS,
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ describe('getPageLayoutTabListInitialActiveTabId', () => {
|
||||
const createMockTab = (id: string): PageLayoutTab => ({
|
||||
id,
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
pageLayoutId: 'page-layout-1',
|
||||
title: `Tab ${id}`,
|
||||
position: 0,
|
||||
|
||||
+1
@@ -10,6 +10,7 @@ describe('getTabsByDisplayMode', () => {
|
||||
const createMockTab = (id: string): PageLayoutTab => ({
|
||||
id,
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
pageLayoutId: 'page-layout-1',
|
||||
title: `Tab ${id}`,
|
||||
position: 0,
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ describe('getTabsWithVisibleWidgets', () => {
|
||||
): PageLayoutTab['widgets'][0] => ({
|
||||
__typename: 'PageLayoutWidget',
|
||||
id,
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: `Widget ${id}`,
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -41,6 +42,7 @@ describe('getTabsWithVisibleWidgets', () => {
|
||||
__typename: 'PageLayoutTab',
|
||||
applicationId: '',
|
||||
id,
|
||||
isActive: true,
|
||||
pageLayoutId: 'page-layout-1',
|
||||
title: `Tab ${id}`,
|
||||
position: 0,
|
||||
|
||||
+2
@@ -10,6 +10,7 @@ import {
|
||||
describe('prepareGridLayoutItemsWithPlaceholders', () => {
|
||||
const createMockWidget = (id: string): PageLayoutWidget => ({
|
||||
id,
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: `Test Widget ${id}`,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -215,6 +216,7 @@ describe('prepareGridLayoutItemsWithPlaceholders', () => {
|
||||
expect(resultWidget.createdAt).toBe(widget.createdAt);
|
||||
expect(resultWidget.updatedAt).toBe(widget.updatedAt);
|
||||
expect(resultWidget.deletedAt).toBe(widget.deletedAt);
|
||||
expect(resultWidget.isActive).toBe(widget.isActive);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
+5
@@ -12,6 +12,7 @@ describe('removeWidgetFromTab', () => {
|
||||
{
|
||||
id: 'tab-1',
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
title: 'Tab 1',
|
||||
position: 0,
|
||||
pageLayoutId: 'layout-1',
|
||||
@@ -19,6 +20,7 @@ describe('removeWidgetFromTab', () => {
|
||||
{
|
||||
__typename: 'PageLayoutWidget' as const,
|
||||
id: 'widget-1',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Widget 1',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -37,6 +39,7 @@ describe('removeWidgetFromTab', () => {
|
||||
{
|
||||
__typename: 'PageLayoutWidget' as const,
|
||||
id: 'widget-2',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-1',
|
||||
title: 'Widget 2',
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -62,6 +65,7 @@ describe('removeWidgetFromTab', () => {
|
||||
{
|
||||
id: 'tab-2',
|
||||
applicationId: '',
|
||||
isActive: true,
|
||||
title: 'Tab 2',
|
||||
position: 1,
|
||||
pageLayoutId: 'layout-1',
|
||||
@@ -69,6 +73,7 @@ describe('removeWidgetFromTab', () => {
|
||||
{
|
||||
__typename: 'PageLayoutWidget' as const,
|
||||
id: 'widget-3',
|
||||
isActive: true,
|
||||
pageLayoutTabId: 'tab-2',
|
||||
title: 'Widget 3',
|
||||
type: WidgetType.IFRAME,
|
||||
|
||||
@@ -28,6 +28,7 @@ export const createDefaultFieldWidget = ({
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title,
|
||||
isActive: true,
|
||||
type: WidgetType.FIELD,
|
||||
configuration: {
|
||||
__typename: 'FieldConfiguration',
|
||||
|
||||
@@ -23,6 +23,7 @@ export const createDefaultFieldsWidget = ({
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title: 'Fields',
|
||||
isActive: true,
|
||||
type: WidgetType.FIELDS,
|
||||
configuration: {
|
||||
__typename: 'FieldsConfiguration',
|
||||
|
||||
+1
@@ -18,6 +18,7 @@ export const createDefaultFrontComponentWidget = (
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title,
|
||||
isActive: true,
|
||||
type: WidgetType.FRONT_COMPONENT,
|
||||
configuration: {
|
||||
__typename: 'FrontComponentConfiguration',
|
||||
|
||||
@@ -72,6 +72,7 @@ export const createDefaultGraphWidget = ({
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title,
|
||||
isActive: true,
|
||||
type: WidgetType.GRAPH,
|
||||
configuration,
|
||||
gridPosition,
|
||||
|
||||
@@ -19,6 +19,7 @@ export const createDefaultIframeWidget = (
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title,
|
||||
isActive: true,
|
||||
type: WidgetType.IFRAME,
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.IFRAME,
|
||||
|
||||
@@ -24,6 +24,7 @@ export const createDefaultRecordTableWidget = ({
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title,
|
||||
isActive: true,
|
||||
type: WidgetType.RECORD_TABLE,
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.RECORD_TABLE,
|
||||
|
||||
+1
@@ -19,6 +19,7 @@ export const createDefaultStandaloneRichTextWidget = (
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title: 'Untitled Rich Text',
|
||||
isActive: true,
|
||||
type: WidgetType.STANDALONE_RICH_TEXT,
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.STANDALONE_RICH_TEXT,
|
||||
|
||||
@@ -15,13 +15,15 @@ export const getTabsWithVisibleWidgets = ({
|
||||
isInSidePanel,
|
||||
isEditMode,
|
||||
}: GetTabsWithVisibleWidgetsParams): PageLayoutTab[] => {
|
||||
const activeTabs = tabs.filter((tab) => tab.isActive);
|
||||
|
||||
if (isEditMode) {
|
||||
return tabs;
|
||||
return activeTabs;
|
||||
}
|
||||
|
||||
const context = buildWidgetVisibilityContext({ isMobile, isInSidePanel });
|
||||
|
||||
const tabsWithFilteredWidgets = tabs.map((tab) => ({
|
||||
const tabsWithFilteredWidgets = activeTabs.map((tab) => ({
|
||||
...tab,
|
||||
widgets: filterVisibleWidgets({ widgets: tab.widgets, context }),
|
||||
}));
|
||||
@@ -30,7 +32,7 @@ export const getTabsWithVisibleWidgets = ({
|
||||
(tab) => tab.widgets.length > 0,
|
||||
);
|
||||
|
||||
if (tabsWithVisibleWidgets.length === 0 && tabs.length > 0) {
|
||||
if (tabsWithVisibleWidgets.length === 0 && activeTabs.length > 0) {
|
||||
return tabsWithFilteredWidgets.slice(0, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ const getRelationFieldWidgetToInsert = (
|
||||
id: `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}${field.id}-${field.label}`,
|
||||
pageLayoutTabId: tabId,
|
||||
title: field.label,
|
||||
isActive: true,
|
||||
type: WidgetType.FIELD,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
|
||||
+4
-13
@@ -9,7 +9,6 @@ import { useResolveFieldMetadataIdFromNameOrId } from '@/page-layout/hooks/useRe
|
||||
import { isFieldWidget } from '@/page-layout/widgets/field/utils/isFieldWidget';
|
||||
import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget';
|
||||
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue';
|
||||
import { indexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/indexViewIdFromObjectMetadataItemFamilySelector';
|
||||
import { styled } from '@linaria/react';
|
||||
@@ -24,7 +23,6 @@ import {
|
||||
TooltipPosition,
|
||||
} from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
|
||||
const StyledLinkContainer = styled.div`
|
||||
@@ -35,21 +33,14 @@ const StyledLinkContainer = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledSeeAllButtonWrapper = styled.div<{ isMobile: boolean }>`
|
||||
opacity: ${({ isMobile }) => (isMobile ? '1' : '0')};
|
||||
pointer-events: none;
|
||||
transition: opacity ${themeCssVariables.animation.duration.instant}s ease;
|
||||
|
||||
.widget:hover & {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
const StyledSeeAllButtonWrapper = styled.div`
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
`;
|
||||
|
||||
export const WidgetActionFieldSeeAll = () => {
|
||||
const widget = useCurrentWidget();
|
||||
const targetRecord = useTargetRecord();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: targetRecord.targetObjectNameSingular,
|
||||
@@ -145,7 +136,7 @@ export const WidgetActionFieldSeeAll = () => {
|
||||
<div id={tooltipId}>
|
||||
<StyledLinkContainer>
|
||||
<Link to={filterLinkHref} data-testid="widget-see-all-link">
|
||||
<StyledSeeAllButtonWrapper isMobile={isMobile}>
|
||||
<StyledSeeAllButtonWrapper>
|
||||
<LightIconButton Icon={IconArrowUpRight} accent="secondary" />
|
||||
</StyledSeeAllButtonWrapper>
|
||||
</Link>
|
||||
|
||||
@@ -205,6 +205,10 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => {
|
||||
variant={variant}
|
||||
hasHeader={showHeader}
|
||||
isEditable={isWidgetEditable}
|
||||
isInVerticalListTab={
|
||||
layoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST
|
||||
}
|
||||
isMobile={isMobile}
|
||||
hasInteractiveContent={widget.type === WidgetType.RECORD_TABLE}
|
||||
>
|
||||
{hasAccess ? (
|
||||
|
||||
+18
@@ -143,6 +143,7 @@ const createPageLayoutWithWidget = (
|
||||
tabs: [
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: TAB_ID_OVERVIEW,
|
||||
title: 'Overview',
|
||||
@@ -252,6 +253,7 @@ export const WithNumberChart: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_NUMBER_CHART,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -338,6 +340,7 @@ export const WithGaugeChart: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_GAUGE_CHART,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -424,6 +427,7 @@ export const WithBarChart: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_BAR_CHART,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -521,6 +525,7 @@ export const SmallWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_SMALL,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -614,6 +619,7 @@ export const MediumWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_MEDIUM,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -711,6 +717,7 @@ export const LargeWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_LARGE,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -808,6 +815,7 @@ export const WideWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_WIDE,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -901,6 +909,7 @@ export const TallWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_TALL,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -999,6 +1008,7 @@ export const WithManyToOneRelationFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_MANY_TO_ONE_RELATION,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1117,6 +1127,7 @@ export const WithOneToManyRelationFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_ONE_TO_MANY_RELATION,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1227,6 +1238,7 @@ export const OneToManyRelationFieldWidgetWithSeeAllButton: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_ONE_TO_MANY_RELATION,
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1363,6 +1375,7 @@ export const OnMobile: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-mobile',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -1460,6 +1473,7 @@ export const InSidePanel: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-side-panel',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
@@ -1617,6 +1631,7 @@ export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
|
||||
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: WIDGET_ID_CATALOG,
|
||||
pageLayoutTabId:
|
||||
variant === 'side-column' ? 'pinned-tab' : TAB_ID_OVERVIEW,
|
||||
@@ -1723,6 +1738,7 @@ export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
|
||||
? [
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: 'pinned-tab',
|
||||
title: 'Pinned Tab',
|
||||
@@ -1735,6 +1751,7 @@ export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
|
||||
},
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: 'other-tab',
|
||||
title: 'Other Tab',
|
||||
@@ -1749,6 +1766,7 @@ export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
|
||||
: [
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: TAB_ID_OVERVIEW,
|
||||
title: 'Overview',
|
||||
|
||||
+11
-43
@@ -1,5 +1,4 @@
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { useRecordFieldsScopeContextOrThrow } from '@/object-record/record-field-list/contexts/RecordFieldsScopeContext';
|
||||
import { RecordDetailMorphRelationSectionDropdown } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdown';
|
||||
import { RecordDetailRelationSectionDropdown } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdown';
|
||||
import {
|
||||
@@ -17,15 +16,11 @@ import {
|
||||
type FieldRelationMetadata,
|
||||
} from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { isFieldMorphRelation } from '@/object-record/record-field/ui/types/guards/isFieldMorphRelation';
|
||||
import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { styled } from '@linaria/react';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
import { IconPencil } from 'twenty-ui/display';
|
||||
import { IconPencil, IconPlus } from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
|
||||
type FieldWidgetRelationEditActionProps = {
|
||||
fieldDefinition:
|
||||
@@ -34,30 +29,15 @@ type FieldWidgetRelationEditActionProps = {
|
||||
recordId: string;
|
||||
};
|
||||
|
||||
const StyledEditButtonWrapper = styled.div<{
|
||||
isDropdownOpen: boolean;
|
||||
isMobile: boolean;
|
||||
}>`
|
||||
opacity: ${({ isDropdownOpen, isMobile }) =>
|
||||
isDropdownOpen ? '1' : isMobile ? '1' : '0'};
|
||||
pointer-events: ${({ isDropdownOpen }) => (isDropdownOpen ? 'auto' : 'none')};
|
||||
transition: ${({ isDropdownOpen }) =>
|
||||
isDropdownOpen
|
||||
? 'none'
|
||||
: `opacity ${themeCssVariables.animation.duration.instant}s ease`};
|
||||
|
||||
.widget:hover & {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
const StyledEditButtonWrapper = styled.div`
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
`;
|
||||
|
||||
export const FieldWidgetRelationEditAction = ({
|
||||
fieldDefinition,
|
||||
recordId,
|
||||
}: FieldWidgetRelationEditActionProps) => {
|
||||
const { scopeInstanceId } = useRecordFieldsScopeContextOrThrow();
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) =>
|
||||
@@ -92,26 +72,14 @@ export const FieldWidgetRelationEditAction = ({
|
||||
|
||||
const isMorphRelation = isFieldMorphRelation(fieldDefinition);
|
||||
|
||||
const relationSelectionDropdownId =
|
||||
getRecordFieldCardRelationPickerDropdownId({
|
||||
fieldDefinition,
|
||||
recordId,
|
||||
instanceId: scopeInstanceId,
|
||||
});
|
||||
|
||||
const isDropdownOpen = useAtomComponentStateValue(
|
||||
isDropdownOpenComponentState,
|
||||
relationSelectionDropdownId,
|
||||
);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const triggerIcon =
|
||||
fieldDefinition.metadata.relationType === RelationType.MANY_TO_ONE
|
||||
? IconPencil
|
||||
: IconPlus;
|
||||
|
||||
const dropdownTriggerClickableComponent = (
|
||||
<StyledEditButtonWrapper
|
||||
isDropdownOpen={isDropdownOpen}
|
||||
isMobile={isMobile}
|
||||
>
|
||||
<LightIconButton Icon={IconPencil} accent="secondary" />
|
||||
<StyledEditButtonWrapper>
|
||||
<LightIconButton Icon={triggerIcon} accent="secondary" />
|
||||
</StyledEditButtonWrapper>
|
||||
);
|
||||
|
||||
|
||||
+18
@@ -291,6 +291,7 @@ const createPageLayoutWithWidget = (
|
||||
tabs: [
|
||||
{
|
||||
__typename: 'PageLayoutTab' as const,
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: TAB_ID_OVERVIEW,
|
||||
title: 'Overview',
|
||||
@@ -332,6 +333,7 @@ export const TextFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-text-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -425,6 +427,7 @@ export const AddressFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-address-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -521,6 +524,7 @@ export const NumberFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-number-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -614,6 +618,7 @@ export const LinkFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-link-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -707,6 +712,7 @@ export const ManyToOneRelationFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-relation-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -810,6 +816,7 @@ export const OneToManyRelationFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-one-to-many-relation-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -905,6 +912,7 @@ export const BooleanFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-boolean-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -997,6 +1005,7 @@ export const CurrencyFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-currency-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1089,6 +1098,7 @@ export const EmailsFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-emails-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1182,6 +1192,7 @@ export const PhonesFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-phones-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1275,6 +1286,7 @@ export const SelectFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-select-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1369,6 +1381,7 @@ export const MultiSelectFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-multi-select-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1466,6 +1479,7 @@ export const TimelineActivityRelationFieldWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-timeline-activity-relation-field',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1564,6 +1578,7 @@ export const ManyToOneRelationCardWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-relation-card',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1675,6 +1690,7 @@ export const OneToManyRelationCardWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-one-to-many-relation-card',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1769,6 +1785,7 @@ export const TimelineActivityRelationCardWidget: Story = {
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-timeline-activity-relation-card',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
@@ -1929,6 +1946,7 @@ export const OneToManyRelationCardWidgetWithProgressiveLoading: Story = {
|
||||
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-one-to-many-relation-card-progressive',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELD,
|
||||
|
||||
+4
@@ -141,6 +141,7 @@ const createPageLayoutWithWidget = (
|
||||
tabs: [
|
||||
{
|
||||
__typename: 'PageLayoutTab' as const,
|
||||
isActive: true,
|
||||
applicationId: '',
|
||||
id: TAB_ID_OVERVIEW,
|
||||
title: 'Overview',
|
||||
@@ -159,6 +160,7 @@ const createPageLayoutWithWidget = (
|
||||
|
||||
const createFieldsWidget = (viewId: string | null): PageLayoutWidget => ({
|
||||
__typename: 'PageLayoutWidget',
|
||||
isActive: true,
|
||||
id: 'widget-fields',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.FIELDS,
|
||||
@@ -213,6 +215,7 @@ const createViewField = (
|
||||
fieldMetadataId,
|
||||
position,
|
||||
isVisible: true,
|
||||
isActive: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
@@ -230,6 +233,7 @@ const createViewFieldGroup = (
|
||||
name,
|
||||
position,
|
||||
isVisible,
|
||||
isActive: true,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
viewFields,
|
||||
});
|
||||
|
||||
+65
-14
@@ -29,9 +29,12 @@ export const useFieldsWidgetGroups = ({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const groups = useMemo<FieldsWidgetGroup[]>(() => {
|
||||
const { groups, displayMode } = useMemo<{
|
||||
groups: FieldsWidgetGroup[];
|
||||
displayMode: FieldsWidgetDisplayMode;
|
||||
}>(() => {
|
||||
if (!isDefined(objectMetadataItem)) {
|
||||
return [];
|
||||
return { groups: [], displayMode: 'grouped' };
|
||||
}
|
||||
|
||||
if (isDefined(view) && isNonEmptyArray(view.viewFieldGroups)) {
|
||||
@@ -41,7 +44,7 @@ export const useFieldsWidgetGroups = ({
|
||||
|
||||
let globalIndex = 0;
|
||||
|
||||
return sortedGroups
|
||||
const resultGroups = sortedGroups
|
||||
.filter((group) => group.isVisible)
|
||||
.map((group) => {
|
||||
const groupFields = [...(group.viewFields ?? [])].sort(
|
||||
@@ -79,28 +82,76 @@ export const useFieldsWidgetGroups = ({
|
||||
};
|
||||
})
|
||||
.filter((group) => group.fields.length > 0);
|
||||
|
||||
return { groups: resultGroups, displayMode: 'grouped' };
|
||||
}
|
||||
|
||||
return filterDraftGroupsForDisplay(
|
||||
buildDefaultFieldsWidgetGroups({
|
||||
fields: objectMetadataItem.fields,
|
||||
objectNameSingular,
|
||||
labelIdentifierFieldMetadataItemId:
|
||||
labelIdentifierFieldMetadataItem?.id,
|
||||
}),
|
||||
);
|
||||
if (isDefined(view) && isNonEmptyArray(view.viewFields)) {
|
||||
let globalIndex = 0;
|
||||
|
||||
const fields: FieldsWidgetGroupField[] = [...view.viewFields]
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.filter((viewField) => viewField.isVisible)
|
||||
.map((viewField) => {
|
||||
const fieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(f) => f.id === viewField.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
fieldMetadataItem,
|
||||
position: viewField.position,
|
||||
isVisible: viewField.isVisible,
|
||||
globalIndex: globalIndex++,
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
return {
|
||||
groups:
|
||||
fields.length > 0
|
||||
? [
|
||||
{
|
||||
id: `${viewId}-ungrouped`,
|
||||
name: '',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
fields,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
displayMode: 'inline',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
groups: filterDraftGroupsForDisplay(
|
||||
buildDefaultFieldsWidgetGroups({
|
||||
fields: objectMetadataItem.fields,
|
||||
objectNameSingular,
|
||||
labelIdentifierFieldMetadataItemId:
|
||||
labelIdentifierFieldMetadataItem?.id,
|
||||
}),
|
||||
),
|
||||
displayMode: 'grouped',
|
||||
};
|
||||
}, [
|
||||
objectMetadataItem,
|
||||
objectNameSingular,
|
||||
labelIdentifierFieldMetadataItem,
|
||||
view,
|
||||
viewId,
|
||||
]);
|
||||
|
||||
const displayMode: FieldsWidgetDisplayMode = 'grouped';
|
||||
|
||||
return {
|
||||
groups,
|
||||
displayMode,
|
||||
isFromView: isDefined(view) && isNonEmptyArray(view.viewFieldGroups),
|
||||
isFromView:
|
||||
isDefined(view) &&
|
||||
(isNonEmptyArray(view.viewFieldGroups) ||
|
||||
isNonEmptyArray(view.viewFields)),
|
||||
};
|
||||
};
|
||||
|
||||
+3
-3
@@ -29,7 +29,7 @@ export const useSaveRecordTableWidgetFiltersToView = (
|
||||
const {
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDelete,
|
||||
performViewFilterGroupAPIDestroy,
|
||||
} = usePerformViewFilterGroupAPIPersist();
|
||||
|
||||
const currentRecordFiltersCallbackState = useAtomComponentStateCallbackState(
|
||||
@@ -142,7 +142,7 @@ export const useSaveRecordTableWidgetFiltersToView = (
|
||||
})),
|
||||
);
|
||||
|
||||
await performViewFilterGroupAPIDelete(
|
||||
await performViewFilterGroupAPIDestroy(
|
||||
viewFilterGroupsToDelete.map((viewFilterGroup) => viewFilterGroup.id),
|
||||
);
|
||||
}, [
|
||||
@@ -155,7 +155,7 @@ export const useSaveRecordTableWidgetFiltersToView = (
|
||||
performViewFilterAPIDelete,
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDelete,
|
||||
performViewFilterGroupAPIDestroy,
|
||||
]);
|
||||
|
||||
return { saveRecordTableWidgetFiltersToView };
|
||||
|
||||
+3
-3
@@ -39,7 +39,7 @@ export const useSaveRecordTableWidgetsViewDataOnDashboardSave = () => {
|
||||
const {
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDelete,
|
||||
performViewFilterGroupAPIDestroy,
|
||||
} = usePerformViewFilterGroupAPIPersist();
|
||||
|
||||
const {
|
||||
@@ -251,7 +251,7 @@ export const useSaveRecordTableWidgetsViewDataOnDashboardSave = () => {
|
||||
},
|
||||
})),
|
||||
);
|
||||
await performViewFilterGroupAPIDelete(
|
||||
await performViewFilterGroupAPIDestroy(
|
||||
viewFilterGroupsToDelete.map((viewFilterGroup) => viewFilterGroup.id),
|
||||
);
|
||||
|
||||
@@ -297,7 +297,7 @@ export const useSaveRecordTableWidgetsViewDataOnDashboardSave = () => {
|
||||
performViewFilterAPIDelete,
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDelete,
|
||||
performViewFilterGroupAPIDestroy,
|
||||
performViewSortAPICreate,
|
||||
performViewSortAPIUpdate,
|
||||
performViewSortAPIDelete,
|
||||
|
||||
+2
@@ -10,6 +10,7 @@ const buildViewField = (
|
||||
id: v4(),
|
||||
fieldMetadataId: v4(),
|
||||
position: 0,
|
||||
isActive: true,
|
||||
isVisible: true,
|
||||
size: 100,
|
||||
aggregateOperation: null,
|
||||
@@ -20,6 +21,7 @@ const buildExistingViewField = (overrides: Partial<ViewField>): ViewField => ({
|
||||
id: v4(),
|
||||
fieldMetadataId: v4(),
|
||||
position: 0,
|
||||
isActive: true,
|
||||
isVisible: true,
|
||||
size: 100,
|
||||
aggregateOperation: null,
|
||||
|
||||
+17
-5
@@ -1,14 +1,20 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { type WidgetCardVariant } from '~/modules/page-layout/widgets/types/WidgetCardVariant';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { type WidgetCardVariant } from '~/modules/page-layout/widgets/types/WidgetCardVariant';
|
||||
|
||||
type WidgetCardContentStyledProps = {
|
||||
variant: WidgetCardVariant;
|
||||
hasHeader: boolean;
|
||||
isEditable: boolean;
|
||||
isInVerticalListTab: boolean;
|
||||
isMobile: boolean;
|
||||
};
|
||||
|
||||
const StyledWidgetCardContent = styled.div<WidgetCardContentStyledProps>`
|
||||
background-color: ${({ variant, isInVerticalListTab, isMobile }) =>
|
||||
variant === 'record-page' && isInVerticalListTab && !isMobile
|
||||
? themeCssVariables.background.secondary
|
||||
: 'transparent'};
|
||||
border: ${({ variant, isEditable }) =>
|
||||
variant === 'record-page' || (variant === 'side-column' && isEditable)
|
||||
? `1px solid ${themeCssVariables.border.color.medium}`
|
||||
@@ -40,10 +46,10 @@ const StyledWidgetCardContent = styled.div<WidgetCardContentStyledProps>`
|
||||
}};
|
||||
|
||||
&:empty {
|
||||
margin-top: ${({ hasHeader, variant, isEditable }) => {
|
||||
if (hasHeader && variant === 'side-column' && !isEditable) return '0';
|
||||
return hasHeader ? themeCssVariables.spacing[2] : '0';
|
||||
}};
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -51,6 +57,8 @@ type WidgetCardContentProps = {
|
||||
variant: WidgetCardVariant;
|
||||
hasHeader: boolean;
|
||||
isEditable: boolean;
|
||||
isInVerticalListTab: boolean;
|
||||
isMobile: boolean;
|
||||
hasInteractiveContent?: boolean;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
@@ -60,6 +68,8 @@ export const WidgetCardContent = ({
|
||||
variant,
|
||||
hasHeader,
|
||||
isEditable,
|
||||
isInVerticalListTab,
|
||||
isMobile,
|
||||
hasInteractiveContent = false,
|
||||
className,
|
||||
children,
|
||||
@@ -77,6 +87,8 @@ export const WidgetCardContent = ({
|
||||
variant={variant}
|
||||
hasHeader={hasHeader}
|
||||
isEditable={isEditable}
|
||||
isInVerticalListTab={isInVerticalListTab}
|
||||
isMobile={isMobile}
|
||||
className={className}
|
||||
onClick={handleContentClick}
|
||||
>
|
||||
|
||||
+1
-25
@@ -10,13 +10,10 @@ import { addWidgetToTab } from '@/page-layout/utils/addWidgetToTab';
|
||||
import { createDefaultFieldWidget } from '@/page-layout/utils/createDefaultFieldWidget';
|
||||
import { createDefaultFieldsWidget } from '@/page-layout/utils/createDefaultFieldsWidget';
|
||||
import { getTabListInstanceIdFromPageLayoutAndRecord } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutAndRecord';
|
||||
import { getWidgetConfigurationViewId } from '@/page-layout/utils/getWidgetConfigurationViewId';
|
||||
import { isVerticalListPosition } from '@/page-layout/utils/isVerticalListPosition';
|
||||
import { removeWidgetFromTab } from '@/page-layout/utils/removeWidgetFromTab';
|
||||
import { useFieldWidgetEligibleFields } from '@/page-layout/widgets/field/hooks/useFieldWidgetEligibleFields';
|
||||
import { getFieldWidgetDefaultDisplayMode } from '@/page-layout/widgets/field/utils/getFieldWidgetDisplayModeConfig';
|
||||
import { useDeleteViewForFieldsWidget } from '@/page-layout/widgets/fields/hooks/useDeleteViewForFieldsWidget';
|
||||
import { useDeleteViewForRecordTableWidget } from '@/page-layout/widgets/record-table/hooks/useDeleteViewForRecordTableWidget';
|
||||
import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup';
|
||||
import { SidePanelList } from '@/side-panel/components/SidePanelList';
|
||||
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
|
||||
@@ -91,11 +88,6 @@ export const SidePanelPageLayoutRecordPageWidgetTypeSelect = () => {
|
||||
const { insertCreatedWidgetAtContext } =
|
||||
useInsertCreatedWidgetAtContext(pageLayoutId);
|
||||
|
||||
const { deleteViewForFieldsWidget } = useDeleteViewForFieldsWidget();
|
||||
|
||||
const { deleteViewForRecordTableWidget } =
|
||||
useDeleteViewForRecordTableWidget();
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: targetObjectNameSingular,
|
||||
});
|
||||
@@ -142,28 +134,11 @@ export const SidePanelPageLayoutRecordPageWidgetTypeSelect = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(existingWidget)) {
|
||||
const viewId = getWidgetConfigurationViewId(existingWidget.configuration);
|
||||
|
||||
if (isDefined(viewId)) {
|
||||
if (existingWidget.type === WidgetType.RECORD_TABLE) {
|
||||
deleteViewForRecordTableWidget(viewId);
|
||||
}
|
||||
|
||||
if (existingWidget.type === WidgetType.FIELDS) {
|
||||
deleteViewForFieldsWidget(viewId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.set(pageLayoutDraftState, (prev) => ({
|
||||
...prev,
|
||||
tabs: removeWidgetFromTab(prev.tabs, tabId, pageLayoutEditingWidgetId),
|
||||
}));
|
||||
}, [
|
||||
deleteViewForFieldsWidget,
|
||||
deleteViewForRecordTableWidget,
|
||||
existingWidget,
|
||||
isReplaceMode,
|
||||
pageLayoutDraftState,
|
||||
pageLayoutEditingWidgetId,
|
||||
@@ -328,6 +303,7 @@ export const SidePanelPageLayoutRecordPageWidgetTypeSelect = () => {
|
||||
const newWidget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: widgetId,
|
||||
isActive: true,
|
||||
pageLayoutTabId: tabId,
|
||||
title: frontComponent.name,
|
||||
type: WidgetType.FRONT_COMPONENT,
|
||||
|
||||
+11
-19
@@ -1,10 +1,11 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import {
|
||||
currentWorkspaceMemberState,
|
||||
type CurrentWorkspaceMember,
|
||||
} from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useColorScheme } from '@/ui/theme/hooks/useColorScheme';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { type WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||
import { resetJotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
|
||||
const updateOneRecordMock = jest.fn();
|
||||
|
||||
@@ -14,11 +15,7 @@ jest.mock('@/object-record/hooks/useUpdateOneRecord', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
const workspaceMember: Omit<
|
||||
WorkspaceMember,
|
||||
'createdAt' | 'updatedAt' | 'userId'
|
||||
> = {
|
||||
__typename: 'WorkspaceMember',
|
||||
const workspaceMember: CurrentWorkspaceMember = {
|
||||
id: 'id',
|
||||
name: {
|
||||
firstName: 'firstName',
|
||||
@@ -31,20 +28,16 @@ const workspaceMember: Omit<
|
||||
|
||||
describe('useColorScheme', () => {
|
||||
it('should update color scheme', async () => {
|
||||
const store = resetJotaiStore();
|
||||
store.set(currentWorkspaceMemberState.atom, workspaceMember);
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<JotaiProvider store={jotaiStore}>{children}</JotaiProvider>
|
||||
<JotaiProvider store={store}>{children}</JotaiProvider>
|
||||
);
|
||||
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
const setCurrentWorkspaceMember = useSetAtomState(
|
||||
currentWorkspaceMemberState,
|
||||
);
|
||||
|
||||
setCurrentWorkspaceMember(workspaceMember);
|
||||
|
||||
return colorScheme;
|
||||
},
|
||||
{
|
||||
@@ -58,7 +51,6 @@ describe('useColorScheme', () => {
|
||||
await result.current.setColorScheme('Dark');
|
||||
});
|
||||
|
||||
// FIXME: For some reason, the color gets unset
|
||||
// expect(result.current.colorScheme).toEqual('Dark');
|
||||
expect(result.current.colorScheme).toEqual('Dark');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ export const VIEW_FIELD_FRAGMENT = gql`
|
||||
size
|
||||
aggregateOperation
|
||||
viewFieldGroupId
|
||||
isActive
|
||||
createdAt
|
||||
updatedAt
|
||||
deletedAt
|
||||
|
||||
@@ -9,6 +9,7 @@ export const VIEW_FIELD_GROUP_FRAGMENT = gql`
|
||||
position
|
||||
isVisible
|
||||
viewId
|
||||
isActive
|
||||
createdAt
|
||||
updatedAt
|
||||
deletedAt
|
||||
|
||||
+5
-5
@@ -104,11 +104,11 @@ export const usePerformViewFilterGroupAPIPersist = () => {
|
||||
[apolloClient],
|
||||
);
|
||||
|
||||
const performViewFilterGroupAPIDelete = useCallback(
|
||||
(viewFilterGroupIdsToDelete: string[]) => {
|
||||
if (!viewFilterGroupIdsToDelete.length) return;
|
||||
const performViewFilterGroupAPIDestroy = useCallback(
|
||||
(viewFilterGroupIdsToDestroy: string[]) => {
|
||||
if (!viewFilterGroupIdsToDestroy.length) return;
|
||||
return Promise.all(
|
||||
viewFilterGroupIdsToDelete.map((viewFilterGroupId) =>
|
||||
viewFilterGroupIdsToDestroy.map((viewFilterGroupId) =>
|
||||
apolloClient.mutate<{ destroyViewFilterGroup: ViewFilterGroup }>({
|
||||
mutation: DESTROY_VIEW_FILTER_GROUP,
|
||||
variables: {
|
||||
@@ -124,6 +124,6 @@ export const usePerformViewFilterGroupAPIPersist = () => {
|
||||
return {
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDelete,
|
||||
performViewFilterGroupAPIDestroy,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { useSaveAnyFieldFilterToView } from '@/views/hooks/useSaveAnyFieldFilterToView';
|
||||
import { useSaveRecordFilterGroupsToViewFilterGroups } from '@/views/hooks/useSaveRecordFilterGroupsToViewFilterGroups';
|
||||
import { useSaveRecordFiltersToViewFilters } from '@/views/hooks/useSaveRecordFiltersToViewFilters';
|
||||
import { useSaveRecordFiltersAndGroupFiltersToViewFiltersAndGroupFilters } from '@/views/hooks/useSaveRecordFiltersAndGroupFiltersToViewFiltersAndGroupFilters';
|
||||
import { useSaveRecordSortsToViewSorts } from '@/views/hooks/useSaveRecordSortsToViewSorts';
|
||||
|
||||
export const useSaveCurrentViewFiltersAndSorts = () => {
|
||||
const { saveRecordFilterGroupsToViewFilterGroups } =
|
||||
useSaveRecordFilterGroupsToViewFilterGroups();
|
||||
|
||||
const { saveRecordFiltersToViewFilters } =
|
||||
useSaveRecordFiltersToViewFilters();
|
||||
const { saveRecordFiltersAndGroupFiltersToViewFiltersAndGroupFilters } =
|
||||
useSaveRecordFiltersAndGroupFiltersToViewFiltersAndGroupFilters();
|
||||
|
||||
const { saveRecordSortsToViewSorts } = useSaveRecordSortsToViewSorts();
|
||||
|
||||
@@ -16,8 +12,7 @@ export const useSaveCurrentViewFiltersAndSorts = () => {
|
||||
|
||||
const saveCurrentViewFilterAndSorts = async () => {
|
||||
await saveRecordSortsToViewSorts();
|
||||
await saveRecordFilterGroupsToViewFilterGroups();
|
||||
await saveRecordFiltersToViewFilters();
|
||||
await saveRecordFiltersAndGroupFiltersToViewFiltersAndGroupFilters();
|
||||
await saveAnyFieldFilterToView();
|
||||
};
|
||||
|
||||
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { usePerformViewFilterGroupAPIPersist } from '@/views/hooks/internal/usePerformViewFilterGroupAPIPersist';
|
||||
import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { getViewFilterGroupsToCreate } from '@/views/utils/getViewFilterGroupsToCreate';
|
||||
import { getViewFilterGroupsToDelete } from '@/views/utils/getViewFilterGroupsToDelete';
|
||||
import { getViewFilterGroupsToUpdate } from '@/views/utils/getViewFilterGroupsToUpdate';
|
||||
import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFilterGroupToViewFilterGroup';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useSaveRecordFilterGroupsToViewFilterGroups = () => {
|
||||
const { canPersistChanges } = useCanPersistViewChanges();
|
||||
const {
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDelete,
|
||||
} = usePerformViewFilterGroupAPIPersist();
|
||||
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const currentRecordFilterGroupsCallbackState =
|
||||
useAtomComponentStateCallbackState(currentRecordFilterGroupsComponentState);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const saveRecordFilterGroupsToViewFilterGroups = useCallback(async () => {
|
||||
if (!canPersistChanges || !isDefined(currentView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentViewFilterGroups = currentView?.viewFilterGroups ?? [];
|
||||
|
||||
const currentRecordFilterGroups = store.get(
|
||||
currentRecordFilterGroupsCallbackState,
|
||||
);
|
||||
|
||||
const newViewFilterGroups = currentRecordFilterGroups.map(
|
||||
(recordFilterGroup) =>
|
||||
mapRecordFilterGroupToViewFilterGroup({
|
||||
recordFilterGroup,
|
||||
view: currentView,
|
||||
}),
|
||||
);
|
||||
|
||||
const viewFilterGroupsToCreate = getViewFilterGroupsToCreate(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterGroupsToDelete = getViewFilterGroupsToDelete(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterGroupsToUpdate = getViewFilterGroupsToUpdate(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterGroupIdsToDelete = viewFilterGroupsToDelete.map(
|
||||
(viewFilterGroup) => viewFilterGroup.id,
|
||||
);
|
||||
|
||||
await performViewFilterGroupAPICreate(
|
||||
viewFilterGroupsToCreate,
|
||||
currentView,
|
||||
);
|
||||
await performViewFilterGroupAPIUpdate(viewFilterGroupsToUpdate);
|
||||
await performViewFilterGroupAPIDelete(viewFilterGroupIdsToDelete);
|
||||
}, [
|
||||
canPersistChanges,
|
||||
currentView,
|
||||
store,
|
||||
currentRecordFilterGroupsCallbackState,
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDelete,
|
||||
]);
|
||||
|
||||
return {
|
||||
saveRecordFilterGroupsToViewFilterGroups,
|
||||
};
|
||||
};
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { type FlatViewFilter } from '@/metadata-store/types/FlatViewFilter';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { usePerformViewFilterAPIPersist } from '@/views/hooks/internal/usePerformViewFilterAPIPersist';
|
||||
import { usePerformViewFilterGroupAPIPersist } from '@/views/hooks/internal/usePerformViewFilterGroupAPIPersist';
|
||||
import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { getViewFilterGroupsToCreate } from '@/views/utils/getViewFilterGroupsToCreate';
|
||||
import { getViewFilterGroupsToDelete } from '@/views/utils/getViewFilterGroupsToDelete';
|
||||
import { getViewFilterGroupsToUpdate } from '@/views/utils/getViewFilterGroupsToUpdate';
|
||||
import { getViewFiltersToCreate } from '@/views/utils/getViewFiltersToCreate';
|
||||
import { getViewFiltersToDelete } from '@/views/utils/getViewFiltersToDelete';
|
||||
import { getViewFiltersToUpdate } from '@/views/utils/getViewFiltersToUpdate';
|
||||
import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFilterGroupToViewFilterGroup';
|
||||
import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useSaveRecordFiltersAndGroupFiltersToViewFiltersAndGroupFilters =
|
||||
() => {
|
||||
const { canPersistChanges } = useCanPersistViewChanges();
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const {
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDestroy,
|
||||
} = usePerformViewFilterGroupAPIPersist();
|
||||
|
||||
const {
|
||||
performViewFilterAPICreate,
|
||||
performViewFilterAPIUpdate,
|
||||
performViewFilterAPIDestroy,
|
||||
} = usePerformViewFilterAPIPersist();
|
||||
|
||||
const currentRecordFilterGroupsCallbackState =
|
||||
useAtomComponentStateCallbackState(
|
||||
currentRecordFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
const currentRecordFiltersCallbackState =
|
||||
useAtomComponentStateCallbackState(currentRecordFiltersComponentState);
|
||||
|
||||
const saveRecordFiltersAndGroupFiltersToViewFiltersAndGroupFilters =
|
||||
useCallback(async () => {
|
||||
if (!canPersistChanges || !isDefined(currentView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentViewFilterGroups = currentView.viewFilterGroups ?? [];
|
||||
const currentRecordFilterGroups = store.get(
|
||||
currentRecordFilterGroupsCallbackState,
|
||||
);
|
||||
|
||||
const newViewFilterGroups = currentRecordFilterGroups.map(
|
||||
(recordFilterGroup) =>
|
||||
mapRecordFilterGroupToViewFilterGroup({
|
||||
recordFilterGroup,
|
||||
view: currentView,
|
||||
}),
|
||||
);
|
||||
|
||||
const viewFilterGroupsToCreate = getViewFilterGroupsToCreate(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterGroupsToDelete = getViewFilterGroupsToDelete(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterGroupsToUpdate = getViewFilterGroupsToUpdate(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterGroupIdsToDestroy = viewFilterGroupsToDelete.map(
|
||||
(viewFilterGroup) => viewFilterGroup.id,
|
||||
);
|
||||
|
||||
await performViewFilterGroupAPICreate(
|
||||
viewFilterGroupsToCreate,
|
||||
currentView,
|
||||
);
|
||||
await performViewFilterGroupAPIUpdate(viewFilterGroupsToUpdate);
|
||||
await performViewFilterGroupAPIDestroy(viewFilterGroupIdsToDestroy);
|
||||
|
||||
// Mirror the DB cascade: remove cascade-deleted viewFilters from the store
|
||||
if (viewFilterGroupIdsToDestroy.length > 0) {
|
||||
const destroyedIdsSet = new Set(viewFilterGroupIdsToDestroy);
|
||||
|
||||
store.set(metadataStoreState.atomFamily('viewFilters'), (prev) => ({
|
||||
...prev,
|
||||
current: (prev.current as FlatViewFilter[]).filter(
|
||||
(viewFilter) =>
|
||||
!isDefined(viewFilter.viewFilterGroupId) ||
|
||||
!destroyedIdsSet.has(viewFilter.viewFilterGroupId),
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
const currentViewFilters = currentView.viewFilters ?? [];
|
||||
const currentRecordFilters = store.get(
|
||||
currentRecordFiltersCallbackState,
|
||||
);
|
||||
|
||||
const newViewFilters = currentRecordFilters.map(
|
||||
mapRecordFilterToViewFilter,
|
||||
);
|
||||
|
||||
const viewFiltersToCreate = getViewFiltersToCreate(
|
||||
currentViewFilters,
|
||||
newViewFilters,
|
||||
);
|
||||
|
||||
const viewFiltersToDelete = getViewFiltersToDelete(
|
||||
currentViewFilters,
|
||||
newViewFilters,
|
||||
).filter(
|
||||
(viewFilter) =>
|
||||
!isDefined(viewFilter.viewFilterGroupId) ||
|
||||
!viewFilterGroupIdsToDestroy.includes(viewFilter.viewFilterGroupId),
|
||||
);
|
||||
|
||||
const viewFiltersToUpdate = getViewFiltersToUpdate(
|
||||
currentViewFilters,
|
||||
newViewFilters,
|
||||
);
|
||||
|
||||
const createViewFilterInputs = viewFiltersToCreate.map(
|
||||
(viewFilter) => ({
|
||||
input: {
|
||||
id: viewFilter.id,
|
||||
fieldMetadataId: viewFilter.fieldMetadataId,
|
||||
viewId: currentView.id,
|
||||
value: viewFilter.value,
|
||||
operand: viewFilter.operand,
|
||||
viewFilterGroupId: viewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
|
||||
subFieldName: viewFilter.subFieldName ?? null,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const updateViewFilterInputs = viewFiltersToUpdate.map(
|
||||
(viewFilter) => ({
|
||||
input: {
|
||||
id: viewFilter.id,
|
||||
update: {
|
||||
value: viewFilter.value,
|
||||
operand: viewFilter.operand,
|
||||
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
|
||||
viewFilterGroupId: viewFilter.viewFilterGroupId,
|
||||
subFieldName: viewFilter.subFieldName ?? null,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const destroyViewFilterInputs = viewFiltersToDelete.map(
|
||||
(viewFilter) => ({
|
||||
input: {
|
||||
id: viewFilter.id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const createResult = await performViewFilterAPICreate(
|
||||
createViewFilterInputs,
|
||||
);
|
||||
if (createResult.status === 'failed') {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateResult = await performViewFilterAPIUpdate(
|
||||
updateViewFilterInputs,
|
||||
);
|
||||
if (updateResult.status === 'failed') {
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteResult = await performViewFilterAPIDestroy(
|
||||
destroyViewFilterInputs,
|
||||
);
|
||||
if (deleteResult.status === 'failed') {
|
||||
return;
|
||||
}
|
||||
}, [
|
||||
canPersistChanges,
|
||||
currentView,
|
||||
store,
|
||||
currentRecordFilterGroupsCallbackState,
|
||||
currentRecordFiltersCallbackState,
|
||||
performViewFilterGroupAPICreate,
|
||||
performViewFilterGroupAPIUpdate,
|
||||
performViewFilterGroupAPIDestroy,
|
||||
performViewFilterAPICreate,
|
||||
performViewFilterAPIUpdate,
|
||||
performViewFilterAPIDestroy,
|
||||
]);
|
||||
|
||||
return {
|
||||
saveRecordFiltersAndGroupFiltersToViewFiltersAndGroupFilters,
|
||||
};
|
||||
};
|
||||
@@ -1,137 +0,0 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { usePerformViewFilterAPIPersist } from '@/views/hooks/internal/usePerformViewFilterAPIPersist';
|
||||
import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges';
|
||||
import { viewsSelector } from '@/views/states/selectors/viewsSelector';
|
||||
import { getViewFiltersToCreate } from '@/views/utils/getViewFiltersToCreate';
|
||||
import { getViewFiltersToDelete } from '@/views/utils/getViewFiltersToDelete';
|
||||
import { getViewFiltersToUpdate } from '@/views/utils/getViewFiltersToUpdate';
|
||||
import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useSaveRecordFiltersToViewFilters = () => {
|
||||
const { canPersistChanges } = useCanPersistViewChanges();
|
||||
const {
|
||||
performViewFilterAPICreate,
|
||||
performViewFilterAPIUpdate,
|
||||
performViewFilterAPIDelete,
|
||||
} = usePerformViewFilterAPIPersist();
|
||||
|
||||
const contextStoreCurrentViewId = useAtomComponentStateValue(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const currentRecordFiltersCallbackState = useAtomComponentStateCallbackState(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const saveRecordFiltersToViewFilters = useCallback(async () => {
|
||||
const views = store.get(viewsSelector.atom);
|
||||
|
||||
const currentView = views.find(
|
||||
(view) => view.id === contextStoreCurrentViewId,
|
||||
);
|
||||
|
||||
if (!isDefined(currentView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canPersistChanges || !isDefined(currentView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentViewFilters = currentView?.viewFilters ?? [];
|
||||
|
||||
const currentRecordFilters = store.get(currentRecordFiltersCallbackState);
|
||||
|
||||
const newViewFilters = currentRecordFilters.map(
|
||||
mapRecordFilterToViewFilter,
|
||||
);
|
||||
|
||||
const viewFiltersToCreate = getViewFiltersToCreate(
|
||||
currentViewFilters,
|
||||
newViewFilters,
|
||||
);
|
||||
|
||||
const viewFiltersToDelete = getViewFiltersToDelete(
|
||||
currentViewFilters,
|
||||
newViewFilters,
|
||||
);
|
||||
|
||||
const viewFiltersToUpdate = getViewFiltersToUpdate(
|
||||
currentViewFilters,
|
||||
newViewFilters,
|
||||
);
|
||||
|
||||
const createViewFilterInputs = viewFiltersToCreate.map((viewFilter) => ({
|
||||
input: {
|
||||
id: viewFilter.id,
|
||||
fieldMetadataId: viewFilter.fieldMetadataId,
|
||||
viewId: currentView.id,
|
||||
value: viewFilter.value,
|
||||
operand: viewFilter.operand,
|
||||
viewFilterGroupId: viewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
|
||||
subFieldName: viewFilter.subFieldName ?? null,
|
||||
},
|
||||
}));
|
||||
|
||||
const updateViewFilterInputs = viewFiltersToUpdate.map((viewFilter) => ({
|
||||
input: {
|
||||
id: viewFilter.id,
|
||||
update: {
|
||||
value: viewFilter.value,
|
||||
operand: viewFilter.operand,
|
||||
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
|
||||
viewFilterGroupId: viewFilter.viewFilterGroupId,
|
||||
subFieldName: viewFilter.subFieldName ?? null,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const deleteViewFilterInputs = viewFiltersToDelete.map((viewFilter) => ({
|
||||
input: {
|
||||
id: viewFilter.id,
|
||||
},
|
||||
}));
|
||||
|
||||
const createResult = await performViewFilterAPICreate(
|
||||
createViewFilterInputs,
|
||||
);
|
||||
if (createResult.status === 'failed') {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateResult = await performViewFilterAPIUpdate(
|
||||
updateViewFilterInputs,
|
||||
);
|
||||
if (updateResult.status === 'failed') {
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteResult = await performViewFilterAPIDelete(
|
||||
deleteViewFilterInputs,
|
||||
);
|
||||
if (deleteResult.status === 'failed') {
|
||||
return;
|
||||
}
|
||||
}, [
|
||||
store,
|
||||
canPersistChanges,
|
||||
currentRecordFiltersCallbackState,
|
||||
performViewFilterAPICreate,
|
||||
performViewFilterAPIUpdate,
|
||||
performViewFilterAPIDelete,
|
||||
contextStoreCurrentViewId,
|
||||
]);
|
||||
|
||||
return {
|
||||
saveRecordFiltersToViewFilters,
|
||||
};
|
||||
};
|
||||
@@ -16,7 +16,7 @@ export const useSaveRecordSortsToViewSorts = () => {
|
||||
const {
|
||||
performViewSortAPICreate,
|
||||
performViewSortAPIUpdate,
|
||||
performViewSortAPIDelete,
|
||||
performViewSortAPIDestroy,
|
||||
} = usePerformViewSortAPIPersist();
|
||||
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
@@ -71,7 +71,7 @@ export const useSaveRecordSortsToViewSorts = () => {
|
||||
},
|
||||
}));
|
||||
|
||||
const deleteViewSortInputs = viewSortsToDelete.map((viewSort) => ({
|
||||
const destroyViewSortInputs = viewSortsToDelete.map((viewSort) => ({
|
||||
input: {
|
||||
id: viewSort.id,
|
||||
},
|
||||
@@ -87,7 +87,7 @@ export const useSaveRecordSortsToViewSorts = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteResult = await performViewSortAPIDelete(deleteViewSortInputs);
|
||||
const deleteResult = await performViewSortAPIDestroy(destroyViewSortInputs);
|
||||
if (deleteResult.status === 'failed') {
|
||||
return;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export const useSaveRecordSortsToViewSorts = () => {
|
||||
currentRecordSortsCallbackState,
|
||||
performViewSortAPICreate,
|
||||
performViewSortAPIUpdate,
|
||||
performViewSortAPIDelete,
|
||||
performViewSortAPIDestroy,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -24,7 +24,7 @@ export const viewsSelector = createAtomSelector<ViewWithRelations[]>({
|
||||
flatObjectMetadataItems.map((item) => [item.id, item]),
|
||||
);
|
||||
|
||||
const flatViewFields = get(metadataStoreState, 'viewFields')
|
||||
const allFlatViewFields = get(metadataStoreState, 'viewFields')
|
||||
.current as FlatViewField[];
|
||||
const flatViewFilters = get(metadataStoreState, 'viewFilters')
|
||||
.current as FlatViewFilter[];
|
||||
@@ -34,9 +34,14 @@ export const viewsSelector = createAtomSelector<ViewWithRelations[]>({
|
||||
.current as FlatViewGroup[];
|
||||
const flatViewFilterGroups = get(metadataStoreState, 'viewFilterGroups')
|
||||
.current as FlatViewFilterGroup[];
|
||||
const flatViewFieldGroups = get(metadataStoreState, 'viewFieldGroups')
|
||||
const allFlatViewFieldGroups = get(metadataStoreState, 'viewFieldGroups')
|
||||
.current as FlatViewFieldGroup[];
|
||||
|
||||
const flatViewFields = allFlatViewFields.filter((field) => field.isActive);
|
||||
const flatViewFieldGroups = allFlatViewFieldGroups.filter(
|
||||
(group) => group.isActive,
|
||||
);
|
||||
|
||||
const viewFieldsByViewId = new Map<string, FlatViewField[]>();
|
||||
const viewFiltersByViewId = new Map<string, FlatViewFilter[]>();
|
||||
const viewSortsByViewId = new Map<string, FlatViewSort[]>();
|
||||
|
||||
@@ -8,6 +8,7 @@ export type ViewField = {
|
||||
viewId?: string;
|
||||
fieldMetadataId: string;
|
||||
position: number;
|
||||
isActive: boolean;
|
||||
isVisible: boolean;
|
||||
size: number;
|
||||
aggregateOperation?: AggregateOperations | null;
|
||||
|
||||
@@ -4,6 +4,7 @@ export type ViewFieldGroup = {
|
||||
id: string;
|
||||
name: string;
|
||||
position: number;
|
||||
isActive: boolean;
|
||||
isVisible: boolean;
|
||||
viewId: string;
|
||||
viewFields: ViewField[];
|
||||
|
||||
@@ -60,6 +60,7 @@ describe('mapViewFieldsToColumnDefinitions', () => {
|
||||
position: 1,
|
||||
size: 1,
|
||||
isVisible: false,
|
||||
isActive: true,
|
||||
definition: {
|
||||
fieldMetadataId: '1',
|
||||
label: 'label 1',
|
||||
@@ -78,6 +79,7 @@ describe('mapViewFieldsToColumnDefinitions', () => {
|
||||
position: 2,
|
||||
size: 2,
|
||||
isVisible: false,
|
||||
isActive: true,
|
||||
definition: {
|
||||
fieldMetadataId: '2',
|
||||
label: 'label 2',
|
||||
@@ -96,6 +98,7 @@ describe('mapViewFieldsToColumnDefinitions', () => {
|
||||
position: 3,
|
||||
size: 3,
|
||||
isVisible: true,
|
||||
isActive: true,
|
||||
definition: {
|
||||
fieldMetadataId: '3',
|
||||
label: 'label 3',
|
||||
@@ -188,6 +191,7 @@ describe('mapColumnDefinitionsToViewFields', () => {
|
||||
fieldMetadataId: 1,
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
isActive: true,
|
||||
definition: columnDefinitions[0],
|
||||
size: undefined,
|
||||
},
|
||||
@@ -197,6 +201,7 @@ describe('mapColumnDefinitionsToViewFields', () => {
|
||||
position: 2,
|
||||
size: 200,
|
||||
isVisible: false,
|
||||
isActive: true,
|
||||
definition: columnDefinitions[1],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -12,6 +12,7 @@ export const mapBoardFieldDefinitionsToViewFields = (
|
||||
size: 0,
|
||||
position: fieldDefinition.position,
|
||||
isVisible: fieldDefinition.isVisible ?? true,
|
||||
isActive: true,
|
||||
definition: fieldDefinition,
|
||||
}),
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user