From e78bc50c20c9026b14008d8e80593a40a250c854 Mon Sep 17 00:00:00 2001 From: Basel Issmail <78056580+issmail-basel@users.noreply.github.com> Date: Thu, 6 Oct 2022 11:55:15 +0300 Subject: [PATCH] feat(web): add content table hook (#266) --- .../Content/ContentListMolecule/index.tsx | 57 +++ .../molecules/Content/ContentTable/index.tsx | 14 +- web/src/components/molecules/Content/types.ts | 19 + .../Project/Content/ContentList/hooks.ts | 44 ++ .../Project/Content/ContentList/index.tsx | 37 +- .../organisms/Project/ModelsMenu/hooks.ts | 7 + web/src/gql/graphql-client-api.tsx | 251 +++++++++++- web/src/gql/graphql.schema.json | 381 +++++++++--------- web/src/gql/queries/item.ts | 57 +++ web/src/state/index.ts | 5 + 10 files changed, 617 insertions(+), 255 deletions(-) create mode 100644 web/src/components/molecules/Content/ContentListMolecule/index.tsx create mode 100644 web/src/components/molecules/Content/types.ts create mode 100644 web/src/components/organisms/Project/Content/ContentList/hooks.ts create mode 100644 web/src/gql/queries/item.ts diff --git a/web/src/components/molecules/Content/ContentListMolecule/index.tsx b/web/src/components/molecules/Content/ContentListMolecule/index.tsx new file mode 100644 index 0000000000..d34fc45434 --- /dev/null +++ b/web/src/components/molecules/Content/ContentListMolecule/index.tsx @@ -0,0 +1,57 @@ +import styled from "@emotion/styled"; + +import Content from "@reearth-cms/components/atoms/Content"; +import PageHeader from "@reearth-cms/components/atoms/PageHeader"; +import { ProColumns } from "@reearth-cms/components/atoms/ProTable"; +import ContentTable from "@reearth-cms/components/molecules/Content/ContentTable"; +import { ContentTableField } from "@reearth-cms/components/molecules/Content/types"; + +export type Props = { + modelName?: string; + contentTableFields?: ContentTableField[]; + contentTableColumns?: ProColumns[]; + modelsMenu: React.ReactNode; +}; + +const ContentListMolecule: React.FC = ({ + modelName, + contentTableFields, + contentTableColumns, + modelsMenu: ModelsMenu, +}) => ( + + {ModelsMenu} + + + + + +); + +const LeftPaneWrapper = styled.div` + width: 200px; +`; + +const PaddedContent = styled(Content)` + margin: 16px; + background-color: #fff; + display: flex; + min-height: 100%; +`; + +const StyledContentTable = styled(ContentTable)` + flex: 1; + background-color: #fff; + padding: 24px; +`; + +const ContentChild = styled.div` + flex: 1; + background-color: #fff; + padding: 24px; +`; + +export default ContentListMolecule; diff --git a/web/src/components/molecules/Content/ContentTable/index.tsx b/web/src/components/molecules/Content/ContentTable/index.tsx index c174ad39ab..07b33f23e4 100644 --- a/web/src/components/molecules/Content/ContentTable/index.tsx +++ b/web/src/components/molecules/Content/ContentTable/index.tsx @@ -1,10 +1,12 @@ import ProTable, { ListToolBarProps, ProColumns } from "@reearth-cms/components/atoms/ProTable"; +import { ContentTableField } from "@reearth-cms/components/molecules/Content/types"; -const columns: ProColumns[] = []; - -const ContentTable: React.FC = () => { - const dataSource: [] = []; +export type Props = { + contentTableFields?: ContentTableField[]; + contentTableColumns?: ProColumns[]; +}; +const ContentTable: React.FC = ({ contentTableFields, contentTableColumns }) => { const handleToolbarEvents: ListToolBarProps | undefined = { search: { onSearch: _ => {}, @@ -13,8 +15,8 @@ const ContentTable: React.FC = () => { return ( { + const [currentModel] = useModel(); + const { data } = useGetItemsQuery({ + variables: { schemaID: currentModel?.schema.id ?? "", first: 100 }, + skip: !currentModel?.schema.id, + }); + + const contentTableFields: ContentTableField[] | undefined = useMemo(() => { + return data?.items.nodes + ?.map(item => + item + ? { + ...item, + fields: item?.fields?.reduce( + (obj, field) => Object.assign(obj, { [field.schemaFieldID]: field.value }), + {}, + ), + } + : undefined, + ) + .filter((contentTableField): contentTableField is ContentTableField => !!contentTableField); + }, [data?.items.nodes]); + + const contentTableColumns: ProColumns[] | undefined = useMemo(() => { + return currentModel?.schema.fields.map(field => ({ + title: field.title, + dataIndex: ["fields", field.id], + key: field.id, + })); + }, [currentModel?.schema.fields]); + + return { + currentModel, + contentTableFields, + contentTableColumns, + }; +}; diff --git a/web/src/components/organisms/Project/Content/ContentList/index.tsx b/web/src/components/organisms/Project/Content/ContentList/index.tsx index b7a69e0990..4226f40282 100644 --- a/web/src/components/organisms/Project/Content/ContentList/index.tsx +++ b/web/src/components/organisms/Project/Content/ContentList/index.tsx @@ -1,15 +1,17 @@ -import styled from "@emotion/styled"; import { useCallback } from "react"; import { useParams, useNavigate } from "react-router-dom"; -import Content from "@reearth-cms/components/atoms/Content"; -import ContentTable from "@reearth-cms/components/molecules/Content/ContentTable"; +import ContentListMolecule from "@reearth-cms/components/molecules/Content/ContentListMolecule"; import ModelsMenu from "@reearth-cms/components/organisms/Project/ModelsMenu"; import { useT } from "@reearth-cms/i18n"; +import useHooks from "./hooks"; + const ContentList: React.FC = () => { const t = useT(); + const { currentModel, contentTableFields, contentTableColumns } = useHooks(); + const navigate = useNavigate(); const { projectId, workspaceId } = useParams(); @@ -22,30 +24,13 @@ const ContentList: React.FC = () => { ); return ( - - - - - - + } + /> ); }; -const PaddedContent = styled(Content)` - margin: 16px; - background-color: #fff; - display: flex; - min-height: 100%; -`; - -const StyledModelsMenu = styled(ModelsMenu)` - width: 200px; -`; - -const ContentChild = styled.div` - flex: 1; - background-color: #fff; - padding: 24px; -`; - export default ContentList; diff --git a/web/src/components/organisms/Project/ModelsMenu/hooks.ts b/web/src/components/organisms/Project/ModelsMenu/hooks.ts index fe23096e2f..87f12e91a8 100644 --- a/web/src/components/organisms/Project/ModelsMenu/hooks.ts +++ b/web/src/components/organisms/Project/ModelsMenu/hooks.ts @@ -7,6 +7,7 @@ import { useCheckModelKeyAvailabilityLazyQuery, Model as GQLModel, } from "@reearth-cms/gql/graphql-client-api"; +import { useModel } from "@reearth-cms/state"; type Params = { projectId?: string; @@ -34,6 +35,7 @@ const fromModel = (model: GQLModel) => ({ }); export default ({ projectId, modelId }: Params) => { + const [currentModel, setCurrentModel] = useModel(); const [modelModalShown, setModelModalShown] = useState(false); const [isKeyAvailable, setIsKeyAvailable] = useState(false); const [CheckModelKeyAvailability, { data: keyData }] = useCheckModelKeyAvailabilityLazyQuery({ @@ -74,6 +76,11 @@ export default ({ projectId, modelId }: Params) => { [rawModel], ); + useEffect(() => { + if (!model || model.id === currentModel?.id) return; + setCurrentModel(model); + }, [model, currentModel, setCurrentModel]); + const [createNewModel] = useCreateModelMutation({ refetchQueries: ["GetModels"], }); diff --git a/web/src/gql/graphql-client-api.tsx b/web/src/gql/graphql-client-api.tsx index 2949a3c9b2..1a7ae7d4bd 100644 --- a/web/src/gql/graphql-client-api.tsx +++ b/web/src/gql/graphql-client-api.tsx @@ -137,7 +137,7 @@ export type CreateIntegrationInput = { export type CreateItemInput = { fields: Array; - modelId: Scalars['ID']; + schemaID: Scalars['ID']; }; export type CreateModelInput = { @@ -210,12 +210,12 @@ export type DeleteIntegrationPayload = { }; export type DeleteItemInput = { - itemId: Scalars['ID']; + itemID: Scalars['ID']; }; export type DeleteItemPayload = { __typename?: 'DeleteItemPayload'; - itemId: Scalars['ID']; + itemID: Scalars['ID']; }; export type DeleteMeInput = { @@ -301,14 +301,9 @@ export enum IntegrationType { export type Item = Node & { __typename?: 'Item'; - createdAt: Scalars['DateTime']; + fields?: Maybe>; id: Scalars['ID']; - latestVersion?: Maybe; - model: Model; - modelId: Scalars['ID']; - publicVersion: Scalars['String']; - updatedAt: Scalars['DateTime']; - versions: Array; + schemaID: Scalars['ID']; }; export type ItemConnection = { @@ -327,12 +322,14 @@ export type ItemEdge = { export type ItemField = { __typename?: 'ItemField'; - fieldId: Scalars['ID']; + schemaFieldID: Scalars['ID']; + type: SchemaFiledType; value: Scalars['Any']; }; export type ItemFieldInput = { - fieldId: Scalars['ID']; + schemaFieldID: Scalars['ID']; + type: SchemaFiledType; value: Scalars['Any']; }; @@ -341,14 +338,6 @@ export type ItemPayload = { item: Item; }; -export type ItemVersion = { - __typename?: 'ItemVersion'; - fields: Array; - parent: Array; - ref: Array; - version: Scalars['String']; -}; - export type KeyAvailability = { __typename?: 'KeyAvailability'; available: Scalars['Boolean']; @@ -742,6 +731,7 @@ export type Query = { nodes: Array>; projects: ProjectConnection; searchUser?: Maybe; + versionsByItem?: Maybe>; }; @@ -774,7 +764,7 @@ export type QueryItemsArgs = { before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; - modelId: Scalars['ID']; + schemaID: Scalars['ID']; }; @@ -812,6 +802,11 @@ export type QuerySearchUserArgs = { nameOrEmail: Scalars['String']; }; + +export type QueryVersionsByItemArgs = { + itemID: Scalars['ID']; +}; + export type RemoveIntegrationFromWorkspaceInput = { integrationId: Scalars['ID']; workspaceId: Scalars['ID']; @@ -1091,7 +1086,7 @@ export type UpdateIntegrationOfWorkspaceInput = { export type UpdateItemInput = { fields: Array; - itemId: Scalars['ID']; + itemID: Scalars['ID']; }; export type UpdateMeInput = { @@ -1164,6 +1159,14 @@ export type User = Node & { name: Scalars['String']; }; +export type VersionedItem = { + __typename?: 'VersionedItem'; + parents?: Maybe>; + refs?: Maybe>>; + value: Item; + version: Scalars['ID']; +}; + export type Webhook = Node & { __typename?: 'Webhook'; active: Scalars['Boolean']; @@ -1328,6 +1331,40 @@ export type UpdateIntegrationMutationVariables = Exact<{ export type UpdateIntegrationMutation = { __typename?: 'Mutation', updateIntegration?: { __typename?: 'IntegrationPayload', integration: { __typename?: 'Integration', id: string, name: string, description?: string | null, logoUrl: string, iType: IntegrationType } } | null }; +export type GetItemsQueryVariables = Exact<{ + schemaID: Scalars['ID']; + first?: InputMaybe; + last?: InputMaybe; + after?: InputMaybe; + before?: InputMaybe; +}>; + + +export type GetItemsQuery = { __typename?: 'Query', items: { __typename?: 'ItemConnection', nodes: Array<{ __typename?: 'Item', id: string, schemaID: string, fields?: Array<{ __typename?: 'ItemField', schemaFieldID: string, type: SchemaFiledType, value: any }> | null } | null> } }; + +export type CreateItemMutationVariables = Exact<{ + schemaID: Scalars['ID']; + fields: Array | ItemFieldInput; +}>; + + +export type CreateItemMutation = { __typename?: 'Mutation', createItem?: { __typename?: 'ItemPayload', item: { __typename?: 'Item', id: string, schemaID: string, fields?: Array<{ __typename?: 'ItemField', value: any, type: SchemaFiledType, schemaFieldID: string }> | null } } | null }; + +export type DeleteItemMutationVariables = Exact<{ + itemID: Scalars['ID']; +}>; + + +export type DeleteItemMutation = { __typename?: 'Mutation', deleteItem?: { __typename?: 'DeleteItemPayload', itemID: string } | null }; + +export type UpdateItemMutationVariables = Exact<{ + itemID: Scalars['ID']; + fields: Array | ItemFieldInput; +}>; + + +export type UpdateItemMutation = { __typename?: 'Mutation', updateItem?: { __typename?: 'ItemPayload', item: { __typename?: 'Item', id: string, schemaID: string, fields?: Array<{ __typename?: 'ItemField', value: any, type: SchemaFiledType, schemaFieldID: string }> | null } } | null }; + export type GetModelsQueryVariables = Exact<{ projectId: Scalars['ID']; first?: InputMaybe; @@ -2128,6 +2165,176 @@ export function useUpdateIntegrationMutation(baseOptions?: Apollo.MutationHookOp export type UpdateIntegrationMutationHookResult = ReturnType; export type UpdateIntegrationMutationResult = Apollo.MutationResult; export type UpdateIntegrationMutationOptions = Apollo.BaseMutationOptions; +export const GetItemsDocument = gql` + query GetItems($schemaID: ID!, $first: Int, $last: Int, $after: Cursor, $before: Cursor) { + items( + schemaID: $schemaID + first: $first + last: $last + after: $after + before: $before + ) { + nodes { + id + schemaID + fields { + schemaFieldID + type + value + } + } + } +} + `; + +/** + * __useGetItemsQuery__ + * + * To run a query within a React component, call `useGetItemsQuery` and pass it any options that fit your needs. + * When your component renders, `useGetItemsQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetItemsQuery({ + * variables: { + * schemaID: // value for 'schemaID' + * first: // value for 'first' + * last: // value for 'last' + * after: // value for 'after' + * before: // value for 'before' + * }, + * }); + */ +export function useGetItemsQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetItemsDocument, options); + } +export function useGetItemsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetItemsDocument, options); + } +export type GetItemsQueryHookResult = ReturnType; +export type GetItemsLazyQueryHookResult = ReturnType; +export type GetItemsQueryResult = Apollo.QueryResult; +export const CreateItemDocument = gql` + mutation CreateItem($schemaID: ID!, $fields: [ItemFieldInput!]!) { + createItem(input: {schemaID: $schemaID, fields: $fields}) { + item { + id + schemaID + fields { + value + type + schemaFieldID + } + } + } +} + `; +export type CreateItemMutationFn = Apollo.MutationFunction; + +/** + * __useCreateItemMutation__ + * + * To run a mutation, you first call `useCreateItemMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateItemMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [createItemMutation, { data, loading, error }] = useCreateItemMutation({ + * variables: { + * schemaID: // value for 'schemaID' + * fields: // value for 'fields' + * }, + * }); + */ +export function useCreateItemMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(CreateItemDocument, options); + } +export type CreateItemMutationHookResult = ReturnType; +export type CreateItemMutationResult = Apollo.MutationResult; +export type CreateItemMutationOptions = Apollo.BaseMutationOptions; +export const DeleteItemDocument = gql` + mutation DeleteItem($itemID: ID!) { + deleteItem(input: {itemID: $itemID}) { + itemID + } +} + `; +export type DeleteItemMutationFn = Apollo.MutationFunction; + +/** + * __useDeleteItemMutation__ + * + * To run a mutation, you first call `useDeleteItemMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteItemMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [deleteItemMutation, { data, loading, error }] = useDeleteItemMutation({ + * variables: { + * itemID: // value for 'itemID' + * }, + * }); + */ +export function useDeleteItemMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(DeleteItemDocument, options); + } +export type DeleteItemMutationHookResult = ReturnType; +export type DeleteItemMutationResult = Apollo.MutationResult; +export type DeleteItemMutationOptions = Apollo.BaseMutationOptions; +export const UpdateItemDocument = gql` + mutation UpdateItem($itemID: ID!, $fields: [ItemFieldInput!]!) { + updateItem(input: {itemID: $itemID, fields: $fields}) { + item { + id + schemaID + fields { + value + type + schemaFieldID + } + } + } +} + `; +export type UpdateItemMutationFn = Apollo.MutationFunction; + +/** + * __useUpdateItemMutation__ + * + * To run a mutation, you first call `useUpdateItemMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useUpdateItemMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [updateItemMutation, { data, loading, error }] = useUpdateItemMutation({ + * variables: { + * itemID: // value for 'itemID' + * fields: // value for 'fields' + * }, + * }); + */ +export function useUpdateItemMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(UpdateItemDocument, options); + } +export type UpdateItemMutationHookResult = ReturnType; +export type UpdateItemMutationResult = Apollo.MutationResult; +export type UpdateItemMutationOptions = Apollo.BaseMutationOptions; export const GetModelsDocument = gql` query GetModels($projectId: ID!, $first: Int, $last: Int, $after: Cursor, $before: Cursor) { models( diff --git a/web/src/gql/graphql.schema.json b/web/src/gql/graphql.schema.json index be7d8e1006..7d47e2b284 100644 --- a/web/src/gql/graphql.schema.json +++ b/web/src/gql/graphql.schema.json @@ -1140,7 +1140,7 @@ "deprecationReason": null }, { - "name": "modelId", + "name": "schemaID", "description": null, "type": { "kind": "NON_NULL", @@ -1706,7 +1706,7 @@ "fields": null, "inputFields": [ { - "name": "itemId", + "name": "itemID", "description": null, "type": { "kind": "NON_NULL", @@ -1732,7 +1732,7 @@ "description": null, "fields": [ { - "name": "itemId", + "name": "itemID", "description": null, "args": [], "type": { @@ -2076,6 +2076,16 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "Float", + "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "SCALAR", "name": "ID", @@ -2372,16 +2382,20 @@ "description": null, "fields": [ { - "name": "createdAt", + "name": "fields", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "ItemField", + "ofType": null + } } }, "isDeprecated": false, @@ -2404,35 +2418,7 @@ "deprecationReason": null }, { - "name": "latestVersion", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "ItemVersion", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "model", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Model", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "modelId", + "name": "schemaID", "description": null, "args": [], "type": { @@ -2446,62 +2432,6 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "publicVersion", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "versions", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "ItemVersion", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, @@ -2647,7 +2577,7 @@ "description": null, "fields": [ { - "name": "fieldId", + "name": "schemaFieldID", "description": null, "args": [], "type": { @@ -2662,6 +2592,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "SchemaFiledType", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "value", "description": null, @@ -2691,7 +2637,7 @@ "fields": null, "inputFields": [ { - "name": "fieldId", + "name": "schemaFieldID", "description": null, "type": { "kind": "NON_NULL", @@ -2707,140 +2653,57 @@ "deprecationReason": null }, { - "name": "value", + "name": "type", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "Any", + "kind": "ENUM", + "name": "SchemaFiledType", "ofType": null } }, "defaultValue": null, "isDeprecated": false, "deprecationReason": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ItemPayload", - "description": null, - "fields": [ + }, { - "name": "item", + "name": "value", "description": null, - "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "Item", + "kind": "SCALAR", + "name": "Any", "ofType": null } }, + "defaultValue": null, "isDeprecated": false, "deprecationReason": null } ], - "inputFields": null, - "interfaces": [], + "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", - "name": "ItemVersion", + "name": "ItemPayload", "description": null, "fields": [ { - "name": "fields", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "ItemField", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "parent", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ref", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", + "name": "item", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "Item", "ofType": null } }, @@ -5578,7 +5441,7 @@ "deprecationReason": null }, { - "name": "modelId", + "name": "schemaID", "description": null, "type": { "kind": "NON_NULL", @@ -5914,6 +5777,43 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "versionsByItem", + "description": null, + "args": [ + { + "name": "itemID", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "VersionedItem", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -8157,7 +8057,7 @@ "deprecationReason": null }, { - "name": "itemId", + "name": "itemID", "description": null, "type": { "kind": "NON_NULL", @@ -8770,6 +8670,85 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "VersionedItem", + "description": null, + "fields": [ + { + "name": "parents", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "refs", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "value", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Item", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "version", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "Webhook", @@ -10291,7 +10270,7 @@ "directives": [ { "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", + "description": "The @deprecated built-in directive is used within the type system definition language to indicate deprecated portions of a GraphQL service's schema, such as deprecated fields on a type, arguments on a field, input fields on an input type, or values of an enum type.", "isRepeatable": false, "locations": [ "ARGUMENT_DEFINITION", @@ -10302,7 +10281,7 @@ "args": [ { "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).", + "description": null, "type": { "kind": "SCALAR", "name": "String", @@ -10398,7 +10377,7 @@ }, { "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", + "description": "The @include directive may be provided for fields, fragment spreads, and inline fragments, and allows for conditional inclusion during execution as described by the if argument.", "isRepeatable": false, "locations": [ "FIELD", @@ -10408,7 +10387,7 @@ "args": [ { "name": "if", - "description": "Included when true.", + "description": null, "type": { "kind": "NON_NULL", "name": null, @@ -10435,7 +10414,7 @@ }, { "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", + "description": "The @skip directive may be provided for fields, fragment spreads, and inline fragments, and allows for conditional exclusion during execution as described by the if argument.", "isRepeatable": false, "locations": [ "FIELD", @@ -10445,7 +10424,7 @@ "args": [ { "name": "if", - "description": "Skipped when true.", + "description": null, "type": { "kind": "NON_NULL", "name": null, @@ -10463,7 +10442,7 @@ }, { "name": "specifiedBy", - "description": "Exposes a URL that specifies the behavior of this scalar.", + "description": "The @specifiedBy built-in directive is used within the type system definition language to provide a scalar specification URL for specifying the behavior of custom scalar types.", "isRepeatable": false, "locations": [ "SCALAR" @@ -10471,7 +10450,7 @@ "args": [ { "name": "url", - "description": "The URL that specifies the behavior of this scalar.", + "description": null, "type": { "kind": "NON_NULL", "name": null, diff --git a/web/src/gql/queries/item.ts b/web/src/gql/queries/item.ts new file mode 100644 index 0000000000..86b1dbbf58 --- /dev/null +++ b/web/src/gql/queries/item.ts @@ -0,0 +1,57 @@ +import { gql } from "@apollo/client"; + +export const GET_ITEMS = gql` + query GetItems($schemaID: ID!, $first: Int, $last: Int, $after: Cursor, $before: Cursor) { + items(schemaID: $schemaID, first: $first, last: $last, after: $after, before: $before) { + nodes { + id + schemaID + fields { + schemaFieldID + type + value + } + } + } + } +`; + +export const CREATE_ITEM = gql` + mutation CreateItem($schemaID: ID!, $fields: [ItemFieldInput!]!) { + createItem(input: { schemaID: $schemaID, fields: $fields }) { + item { + id + schemaID + fields { + value + type + schemaFieldID + } + } + } + } +`; + +export const DELETE_ITEM = gql` + mutation DeleteItem($itemID: ID!) { + deleteItem(input: { itemID: $itemID }) { + itemID + } + } +`; + +export const UPDATE_ITEM = gql` + mutation UpdateItem($itemID: ID!, $fields: [ItemFieldInput!]!) { + updateItem(input: { itemID: $itemID, fields: $fields }) { + item { + id + schemaID + fields { + value + type + schemaFieldID + } + } + } + } +`; diff --git a/web/src/state/index.ts b/web/src/state/index.ts index 9ae11d9040..0f593951d5 100644 --- a/web/src/state/index.ts +++ b/web/src/state/index.ts @@ -1,5 +1,7 @@ import { atom, useAtom } from "jotai"; +import { Model } from "@reearth-cms/components/molecules/Schema/types"; + // useError is needed for Apollo provider error only. const error = atom(undefined); export const useError = () => useAtom(error); @@ -14,3 +16,6 @@ export type Workspace = { }; const workspace = atom(undefined); export const useWorkspace = () => useAtom(workspace); + +const model = atom(undefined); +export const useModel = () => useAtom(model);