feat: create default opportunities view on workspace creation + add seed data (#1461)
Closes #1314
This commit is contained in:
@ -2495,7 +2495,7 @@ export type ViewField = {
|
|||||||
key: Scalars['String'];
|
key: Scalars['String'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
objectId: Scalars['String'];
|
objectId: Scalars['String'];
|
||||||
size: Scalars['Int'];
|
size?: Maybe<Scalars['Int']>;
|
||||||
view: View;
|
view: View;
|
||||||
viewId: Scalars['String'];
|
viewId: Scalars['String'];
|
||||||
};
|
};
|
||||||
@ -2506,7 +2506,7 @@ export type ViewFieldCreateInput = {
|
|||||||
key: Scalars['String'];
|
key: Scalars['String'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
objectId: Scalars['String'];
|
objectId: Scalars['String'];
|
||||||
size: Scalars['Int'];
|
size?: InputMaybe<Scalars['Int']>;
|
||||||
view: ViewCreateNestedOneWithoutFieldsInput;
|
view: ViewCreateNestedOneWithoutFieldsInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2516,7 +2516,7 @@ export type ViewFieldCreateManyInput = {
|
|||||||
key: Scalars['String'];
|
key: Scalars['String'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
objectId: Scalars['String'];
|
objectId: Scalars['String'];
|
||||||
size: Scalars['Int'];
|
size?: InputMaybe<Scalars['Int']>;
|
||||||
viewId: Scalars['String'];
|
viewId: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2592,7 +2592,7 @@ export type ViewFieldWhereInput = {
|
|||||||
key?: InputMaybe<StringFilter>;
|
key?: InputMaybe<StringFilter>;
|
||||||
name?: InputMaybe<StringFilter>;
|
name?: InputMaybe<StringFilter>;
|
||||||
objectId?: InputMaybe<StringFilter>;
|
objectId?: InputMaybe<StringFilter>;
|
||||||
size?: InputMaybe<IntFilter>;
|
size?: InputMaybe<IntNullableFilter>;
|
||||||
view?: InputMaybe<ViewRelationFilter>;
|
view?: InputMaybe<ViewRelationFilter>;
|
||||||
viewId?: InputMaybe<StringFilter>;
|
viewId?: InputMaybe<StringFilter>;
|
||||||
};
|
};
|
||||||
@ -3520,7 +3520,7 @@ export type UpdateViewFieldMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type UpdateViewFieldMutation = { __typename?: 'Mutation', updateOneViewField: { __typename?: 'ViewField', index: number, isVisible: boolean, key: string, name: string, size: number } };
|
export type UpdateViewFieldMutation = { __typename?: 'Mutation', updateOneViewField: { __typename?: 'ViewField', index: number, isVisible: boolean, key: string, name: string, size?: number | null } };
|
||||||
|
|
||||||
export type UpdateViewFilterMutationVariables = Exact<{
|
export type UpdateViewFilterMutationVariables = Exact<{
|
||||||
data: ViewFilterUpdateInput;
|
data: ViewFilterUpdateInput;
|
||||||
@ -3544,7 +3544,7 @@ export type GetViewFieldsQueryVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type GetViewFieldsQuery = { __typename?: 'Query', viewFields: Array<{ __typename?: 'ViewField', index: number, isVisible: boolean, key: string, name: string, size: number }> };
|
export type GetViewFieldsQuery = { __typename?: 'Query', viewFields: Array<{ __typename?: 'ViewField', index: number, isVisible: boolean, key: string, name: string, size?: number | null }> };
|
||||||
|
|
||||||
export type GetViewFiltersQueryVariables = Exact<{
|
export type GetViewFiltersQueryVariables = Exact<{
|
||||||
where?: InputMaybe<ViewFilterWhereInput>;
|
where?: InputMaybe<ViewFilterWhereInput>;
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import type {
|
import type { ViewFieldMetadata } from '@/ui/editable-field/types/ViewField';
|
||||||
ViewFieldMetadata,
|
|
||||||
ViewFieldTextMetadata,
|
|
||||||
} from '@/ui/editable-field/types/ViewField';
|
|
||||||
import { availableTableColumnsScopedState } from '@/ui/table/states/availableTableColumnsScopedState';
|
import { availableTableColumnsScopedState } from '@/ui/table/states/availableTableColumnsScopedState';
|
||||||
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { savedTableColumnsScopedState } from '@/ui/table/states/savedTableColumnsScopedState';
|
import { savedTableColumnsScopedState } from '@/ui/table/states/savedTableColumnsScopedState';
|
||||||
@ -20,14 +17,9 @@ import {
|
|||||||
useGetViewFieldsQuery,
|
useGetViewFieldsQuery,
|
||||||
useUpdateViewFieldMutation,
|
useUpdateViewFieldMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
|
import { assertNotNull } from '~/utils/assert';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
const DEFAULT_VIEW_FIELD_METADATA: ViewFieldTextMetadata = {
|
|
||||||
type: 'text',
|
|
||||||
placeHolder: '',
|
|
||||||
fieldName: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
const toViewFieldInput = (
|
const toViewFieldInput = (
|
||||||
objectId: 'company' | 'person',
|
objectId: 'company' | 'person',
|
||||||
fieldDefinition: ColumnDefinition<ViewFieldMetadata>,
|
fieldDefinition: ColumnDefinition<ViewFieldMetadata>,
|
||||||
@ -119,7 +111,6 @@ export const useTableViewFields = ({
|
|||||||
variables: {
|
variables: {
|
||||||
orderBy: { index: SortOrder.Asc },
|
orderBy: { index: SortOrder.Asc },
|
||||||
where: {
|
where: {
|
||||||
objectId: { equals: objectId },
|
|
||||||
viewId: { equals: currentTableViewId },
|
viewId: { equals: currentTableViewId },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -130,18 +121,24 @@ export const useTableViewFields = ({
|
|||||||
return refetch();
|
return refetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextColumns = data.viewFields.map<
|
const nextColumns = data.viewFields
|
||||||
ColumnDefinition<ViewFieldMetadata>
|
.map<ColumnDefinition<ViewFieldMetadata> | null>((viewField) => {
|
||||||
>((viewField) => ({
|
const columnDefinition = columnDefinitions.find(
|
||||||
...(columnDefinitions.find(({ key }) => viewField.key === key) || {
|
({ key }) => viewField.key === key,
|
||||||
metadata: DEFAULT_VIEW_FIELD_METADATA,
|
);
|
||||||
}),
|
|
||||||
key: viewField.key,
|
return columnDefinition
|
||||||
name: viewField.name,
|
? {
|
||||||
index: viewField.index,
|
...columnDefinition,
|
||||||
size: viewField.size,
|
key: viewField.key,
|
||||||
isVisible: viewField.isVisible,
|
name: viewField.name,
|
||||||
}));
|
index: viewField.index,
|
||||||
|
size: viewField.size ?? columnDefinition.size,
|
||||||
|
isVisible: viewField.isVisible,
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
})
|
||||||
|
.filter<ColumnDefinition<ViewFieldMetadata>>(assertNotNull);
|
||||||
|
|
||||||
if (!isDeeplyEqual(tableColumns, nextColumns)) {
|
if (!isDeeplyEqual(tableColumns, nextColumns)) {
|
||||||
setSavedTableColumns(nextColumns);
|
setSavedTableColumns(nextColumns);
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { tableColumnsScopedState } from '@/ui/table/states/tableColumnsScopedSta
|
|||||||
import { currentTableViewIdState } from '@/ui/table/states/tableViewsState';
|
import { currentTableViewIdState } from '@/ui/table/states/tableViewsState';
|
||||||
import type { ColumnDefinition } from '@/ui/table/types/ColumnDefinition';
|
import type { ColumnDefinition } from '@/ui/table/types/ColumnDefinition';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
|
import { ViewType } from '~/generated/graphql';
|
||||||
|
|
||||||
import { useTableViewFields } from './useTableViewFields';
|
import { useTableViewFields } from './useTableViewFields';
|
||||||
import { useViewFilters } from './useViewFilters';
|
import { useViewFilters } from './useViewFilters';
|
||||||
@ -44,6 +45,7 @@ export const useTableViews = <Entity, SortField>({
|
|||||||
const { handleViewsChange, isFetchingViews } = useViews({
|
const { handleViewsChange, isFetchingViews } = useViews({
|
||||||
objectId,
|
objectId,
|
||||||
onViewCreate: handleViewCreate,
|
onViewCreate: handleViewCreate,
|
||||||
|
type: ViewType.Table,
|
||||||
});
|
});
|
||||||
const { createViewFields, persistColumns } = useTableViewFields({
|
const { createViewFields, persistColumns } = useTableViewFields({
|
||||||
objectId,
|
objectId,
|
||||||
|
|||||||
@ -24,9 +24,11 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
|||||||
export const useViews = ({
|
export const useViews = ({
|
||||||
objectId,
|
objectId,
|
||||||
onViewCreate,
|
onViewCreate,
|
||||||
|
type,
|
||||||
}: {
|
}: {
|
||||||
objectId: 'company' | 'person';
|
objectId: 'company' | 'person';
|
||||||
onViewCreate: (viewId: string) => Promise<void>;
|
onViewCreate: (viewId: string) => Promise<void>;
|
||||||
|
type: ViewType;
|
||||||
}) => {
|
}) => {
|
||||||
const [currentTableViewId, setCurrentTableViewId] = useRecoilScopedState(
|
const [currentTableViewId, setCurrentTableViewId] = useRecoilScopedState(
|
||||||
currentTableViewIdState,
|
currentTableViewIdState,
|
||||||
@ -86,6 +88,7 @@ export const useViews = ({
|
|||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
objectId: { equals: objectId },
|
objectId: { equals: objectId },
|
||||||
|
type: { equals: type },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onCompleted: (data) => {
|
onCompleted: (data) => {
|
||||||
|
|||||||
@ -97,5 +97,28 @@
|
|||||||
"size": 150
|
"size": 150
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "All Opportunities",
|
||||||
|
"objectId": "company",
|
||||||
|
"type": "Pipeline",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "closeDate",
|
||||||
|
"name": "Close Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "amount",
|
||||||
|
"name": "Amount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "probability",
|
||||||
|
"name": "Probability"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pointOfContact",
|
||||||
|
"name": "Point of Contact"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "viewFields" ALTER COLUMN "size" DROP NOT NULL;
|
||||||
@ -662,7 +662,7 @@ model ViewField {
|
|||||||
key String
|
key String
|
||||||
name String
|
name String
|
||||||
objectId String
|
objectId String
|
||||||
size Int
|
size Int?
|
||||||
|
|
||||||
view View @relation(fields: [viewId], references: [id], onDelete: Cascade)
|
view View @relation(fields: [viewId], references: [id], onDelete: Cascade)
|
||||||
viewId String
|
viewId String
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export const seedViews = async (prisma: PrismaClient) => {
|
|||||||
const workspaceId = 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419';
|
const workspaceId = 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419';
|
||||||
const companyViewId = 'twenty-5e924b69-a619-41bf-bd31-a9e8551fc9d1';
|
const companyViewId = 'twenty-5e924b69-a619-41bf-bd31-a9e8551fc9d1';
|
||||||
const personViewId = 'twenty-db9e6c85-c091-4fd6-88b1-c1830f5e90d1';
|
const personViewId = 'twenty-db9e6c85-c091-4fd6-88b1-c1830f5e90d1';
|
||||||
|
const opportunitiesViewId = 'twenty-6abb47a2-7a91-4679-a538-59946f0c06a9';
|
||||||
|
|
||||||
await prisma.view.upsert({
|
await prisma.view.upsert({
|
||||||
where: { id: companyViewId },
|
where: { id: companyViewId },
|
||||||
@ -149,4 +150,52 @@ export const seedViews = async (prisma: PrismaClient) => {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await prisma.view.upsert({
|
||||||
|
where: { id: opportunitiesViewId },
|
||||||
|
update: {},
|
||||||
|
create: {
|
||||||
|
id: opportunitiesViewId,
|
||||||
|
name: 'All Opportunities',
|
||||||
|
objectId: 'company',
|
||||||
|
type: 'Pipeline',
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
key: 'closeDate',
|
||||||
|
name: 'Close Date',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'amount',
|
||||||
|
name: 'Amount',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'probability',
|
||||||
|
name: 'Probability',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'pointOfContact',
|
||||||
|
name: 'Point of Contact',
|
||||||
|
},
|
||||||
|
].map((viewField, index) =>
|
||||||
|
prisma.viewField.upsert({
|
||||||
|
where: {
|
||||||
|
viewId_key: { key: viewField.key, viewId: opportunitiesViewId },
|
||||||
|
},
|
||||||
|
update: {},
|
||||||
|
create: {
|
||||||
|
...viewField,
|
||||||
|
index,
|
||||||
|
isVisible: true,
|
||||||
|
objectId: 'company',
|
||||||
|
viewId: opportunitiesViewId,
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user