[GraphQL] refactoring of endpoints

Mostly, it's about reducing their number and making things cleaner.

E.g. tree is not a different request, but a combination of various
"nodes" requests to get children/parent.
parent 931051af
Pipeline #7589 failed with stages
in 18 minutes and 45 seconds
<!--
* Copyright (c) 2021 GraphQL Contributors
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
This is a copy-paste from
https://github.com/graphql/graphiql/tree/main/examples/graphiql-cdn
adjusted to get the GGTX bearer token.
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GraphiQL 4 with React 19 and GraphiQL Explorer</title>
<style>
body {
margin: 0;
overflow: hidden; /* in Firefox */
}
#graphiql {
height: 100dvh;
}
.loading {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 4rem;
}
</style>
<link
rel="stylesheet"
href="https://esm.sh/graphiql@4.0.0/dist/style.css"
/>
<link
rel="stylesheet"
href="https://esm.sh/@graphiql/plugin-explorer@4.0.0/dist/style.css"
/>
<!-- Note: the ?standalone flag bundles the module along with all of its `dependencies`, excluding `peerDependencies`, into a single JavaScript file. -->
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@19.1.0",
"react/jsx-runtime": "https://esm.sh/react@19.1.0/jsx-runtime",
"react-dom": "https://esm.sh/react-dom@19.1.0",
"react-dom/client": "https://esm.sh/react-dom@19.1.0/client",
"graphiql": "https://esm.sh/graphiql@4.0.0?standalone&external=react,react/jsx-runtime,react-dom,@graphiql/react",
"@graphiql/plugin-explorer": "https://esm.sh/@graphiql/plugin-explorer@4.0.0?standalone&external=react,react/jsx-runtime,react-dom,@graphiql/react,graphql",
"@graphiql/react": "https://esm.sh/@graphiql/react@0.30.0?standalone&external=react,react/jsx-runtime,react-dom,graphql,@graphiql/toolkit",
"@graphiql/toolkit": "https://esm.sh/@graphiql/toolkit@0.11.2?standalone&external=graphql",
"graphql": "https://esm.sh/graphql@16.11.0"
}
}
</script>
<script type="module">
// Import React and ReactDOM
import React from 'react';
import ReactDOM from 'react-dom/client';
// Import GraphiQL and the Explorer plugin
import { GraphiQL } from 'graphiql';
import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { explorerPlugin } from '@graphiql/plugin-explorer';
// find gargantext local storage session cookie
const sessions = JSON.parse(localStorage.getItem('garg-sessions')) || [];
const token = (sessions.filter((s) => s.backend.baseUrl == window.location.origin)[0] || {}).token;
console.log('found token', token);
const fetcher = createGraphiQLFetcher({
// url: 'https://countries.trevorblades.com',
url: 'http://localhost:8008/gql',
headers: {
'Authorization': `Bearer ${token}`,
},
});
const explorer = explorerPlugin();
function App() {
return React.createElement(GraphiQL, {
fetcher,
plugins: [explorer],
});
}
const container = document.getElementById('graphiql');
const root = ReactDOM.createRoot(container);
root.render(React.createElement(App));
</script>
</head>
<body>
<div id="graphiql">
<div class="loading">Loading…</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="SwaggerUI" />
<title>SwaggerUI</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js" crossorigin></script>
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
url: `${window.location.origin}/swagger.json`,
dom_id: '#swagger-ui',
});
};
</script>
</body>
</html>
......@@ -1020,7 +1020,7 @@
"debouncing": "0.1.2",
"graphql-client": {
"git": "https://github.com/OxfordAbstracts/purescript-graphql-client",
"ref": "v10.0.3",
"ref": "694551e8baa992310eedf0a9d90f6e23b2e8d964",
"dependencies": [
"aff",
"affjax",
......@@ -1780,7 +1780,7 @@
"graphql-client": {
"type": "git",
"url": "https://github.com/OxfordAbstracts/purescript-graphql-client",
"rev": "7f85c4d64ab4b767ecc999429c1c37f7a6ad4816",
"rev": "694551e8baa992310eedf0a9d90f6e23b2e8d964",
"dependencies": [
"aff",
"affjax",
......
......@@ -20,7 +20,8 @@ workspace:
# https://github.com/OxfordAbstracts/purescript-graphql-client/issues/138
graphql-client:
git: https://github.com/OxfordAbstracts/purescript-graphql-client
ref: v10.0.3
ref: 694551e8baa992310eedf0a9d90f6e23b2e8d964
#ref: v10.0.3
dependencies:
- aff
- affjax
......
......@@ -17,7 +17,7 @@ import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), SpinnerTheme(..))
import Gargantext.Components.Category (ratingSimpleLoader)
import Gargantext.Components.Document.Types (DocPath, Document(..), LoadedData, initialState)
import Gargantext.Components.GraphQL.Endpoints (getContextNgrams)
import Gargantext.Components.GraphQL.Endpoints (getNgramsForContextAndList)
import Gargantext.Components.NgramsTable.AutoSync (useAutoSync)
import Gargantext.Components.Node (NodePoly(..))
import Gargantext.Core.NgramsTable.Functions (addNewNgramA, applyNgramsPatches, coreDispatch, findNgramRoot, setTermListA, computeCache)
......@@ -76,7 +76,7 @@ layoutCpt = R2.hereComponent here "layout" hCpt
useLoader
{ errorHandler: Nothing
, herePrefix: hp
, loader: \p -> getContextNgrams session p.contextId p.listId
, loader: \p -> getNgramsForContextAndList session p.contextId p.listId
, path: { contextId: nodeId, listId }
, render: \contextNgrams ->
layoutWithContextNgrams $ Record.merge props { contextNgrams }
......
......@@ -6,6 +6,7 @@ import DOM.Simple (window)
import Data.Array as A
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Traversable (traverse_)
import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Gargantext.AsyncTasks as GAT
......@@ -27,12 +28,12 @@ import Gargantext.Components.Forest.Tree.Node.Action.Update (updateRequest)
import Gargantext.Components.Forest.Tree.Node.Action.Upload (uploadArbitraryFile, uploadFile)
import Gargantext.Components.Forest.Tree.Node.Box (nodePopupView)
import Gargantext.Components.Forest.Tree.Node.Tools.SubTree.Types (SubTreeOut(..))
import Gargantext.Components.GraphQL.Endpoints (getNode, getTreeFirstLevel)
import Gargantext.Components.GraphQL.Endpoints (getNodeById, getTreeFirstLevel)
import Gargantext.Components.GraphQL.Node (Node)
import Gargantext.Components.GraphQL.Tree (TreeFirstLevel, TreeNode)
import Gargantext.Components.GraphQL.Tree (TreeFirstLevel)
import Gargantext.Config.REST (AffRESTError)
import Gargantext.Config.Utils (handleRESTError)
import Gargantext.Hooks.LinkHandler (useLinkHandler)
import Gargantext.Hooks.LinkHandler (useLinkHandler, Methods)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes (AppRoute(Home), appPath, nodeTypeAppRoute)
import Gargantext.Sessions (Session(..), sessionId)
......@@ -101,10 +102,10 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt
$ parent
<> childrenEl
makeFolderElements :: Array TreeNode -> Record FolderViewProps -> Array R.Element
makeFolderElements :: Array Node -> Record FolderViewProps -> Array R.Element
makeFolderElements folders' props = makeFolderElementsMap <$> folders'
where
makeFolderElementsMap :: TreeNode -> R.Element
makeFolderElementsMap :: Node -> R.Element
makeFolderElementsMap node = folder
{ nodeId: node.id
, linkId: node.id
......@@ -117,7 +118,7 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt
, text: node.name
}
makeParentFolder :: TreeNode -> Maybe TreeNode -> Record FolderViewProps -> Array R.Element
makeParentFolder :: Node -> Maybe Node -> Record FolderViewProps -> Array R.Element
makeParentFolder root (Just parent) props =
[ folder
{ linkId: parent.id
......@@ -133,7 +134,7 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt
]
makeParentFolder _ Nothing _ = []
sortFolders :: TreeNode -> TreeNode -> Ordering
sortFolders :: Node -> Node -> Ordering
sortFolders a b = compare a.id b.id
type FolderProps =
......@@ -298,7 +299,9 @@ backButtonSmartMainCpt = here.component "backButtonSmartMain" cpt
[ H.i { className: "fa fa-arrow-left", title: "Previous view" } []
]
where
action rootId pId handlers
action :: Int -> Maybe Int -> Record Methods -> Effect Unit
action _rootId Nothing _handlers = pure unit
action rootId (Just pId) handlers
| rootId == pId = handlers.goToRoute Home
| otherwise = handlers.goToPreviousPage unit
......@@ -315,7 +318,7 @@ loadFolders :: Record LoadProps -> AffRESTError TreeFirstLevel
loadFolders { nodeId, session } = getTreeFirstLevel session nodeId
loadNode :: Record LoadProps -> AffRESTError Node
loadNode { nodeId, session } = getNode session nodeId
loadNode { nodeId, session } = getNodeById session nodeId
type PerformActionProps =
( boxes :: Boxes
......
......@@ -11,7 +11,8 @@ import Data.String (Pattern(..), split)
import Gargantext.Components.App.Store as Store
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.GraphQL.Endpoints (getBreadcrumb, getNodeChildren, getNodeParent)
import Gargantext.Components.GraphQL.Tree (BreadcrumbInfo, TreeNode)
import Gargantext.Components.GraphQL.Node (Node)
import Gargantext.Components.GraphQL.Tree (BreadcrumbInfo)
import Gargantext.Config.REST (AffRESTError)
import Gargantext.Ends (Backend(..))
import Gargantext.Hooks.Loader (useLoader)
......@@ -195,10 +196,10 @@ breadcrumbViewMainCpt = here.component "breadcrumbViewMainCpt" cpt
pure $
R.fragment items
makeBreadcrumbElements :: Array TreeNode -> Session -> String -> Boolean -> Array R.Element
makeBreadcrumbElements :: Array Node -> Session -> String -> Boolean -> Array R.Element
makeBreadcrumbElements items' session format openTreeNodes = makeBreadcrumbElementsMap <$> items'
where
makeBreadcrumbElementsMap :: TreeNode -> R.Element
makeBreadcrumbElementsMap :: Node -> R.Element
makeBreadcrumbElementsMap node = breadcrumbItem
{ linkId: node.id
, linkNodeType: node.node_type
......@@ -353,8 +354,8 @@ loadBreadcrumbData { route: CorpusDocument _s corpusId listId documentId, sessio
loadBreadcrumbData { route: Dashboard _s nodeId, session } = do
loadBreadcrumbDataRaw { nodeId, session }
loadBreadcrumbData { route: Document _s listId documentId, session } = do
corpora <- getNodeParent session listId GT.Corpus
let nodeId = maybe listId _.id $ either (const Nothing) A.head corpora
corpus <- getNodeParent session listId GT.Corpus
let nodeId = either (const listId) _.id corpus
loadBreadcrumbDataRaw { nodeId, session }
loadBreadcrumbData { route: Folder _s nodeId, session } = do
loadBreadcrumbDataRaw { nodeId, session }
......
......@@ -260,16 +260,17 @@ nodeSpanCpt = here.component "nodeSpan" cpt
NT.NUpdateWorkerProgress ji atl -> do
-- TODO Fire this only once!
here.log3 "[nodeSpan] update job progress" ji atl
let wtl = GT.WorkerTaskWithLog { task: ji, lastLog: Just atl }
if GT.asyncTaskLogIsFinished atl then do
-- Handle error but only when the task is not already in the storage
-- (we want to avoid reporting the error multiple times, from different places).
-- See e.g. https://gitlab.iscpif.fr/gargantext/purescript-gargantext/issues/728
-- (error is thrown before the task marks any progress)
hasTask <- GAT.hasTask props.id ji boxes.tasks
hasTask <- GAT.hasTask props.id wtl boxes.tasks
unless hasTask $ do
handleErrorInAsyncTaskLog boxes.errors atl
else do
GAT.insert props.id ji boxes.tasks
GAT.insert props.id wtl boxes.tasks
_ -> pure unit
ws <- T.read boxes.wsNotification
let action = NT.InsertCallback (NT.UpdateTree props.id) ("node-span-" <> show props.id) cb
......
......@@ -25,6 +25,8 @@ import Gargantext.Routes (AppRoute)
import Gargantext.Sessions (Session(..))
import Gargantext.Types (NodeType)
import Gargantext.Utils.Reactix as R2
import GraphQL.Client.Args (OrArg, IgnoreArg, AndArg)
import GraphQL.Client.AsGql (AsGql)
import GraphQL.Client.BaseClients.Urql (UrqlClient, createClient)
import GraphQL.Client.Operation (OpMutation, OpQuery)
import GraphQL.Client.Query (decodeGqlRes) --, mutationJson)
......@@ -32,6 +34,7 @@ import GraphQL.Client.SafeQueryName (safeQueryName)
import GraphQL.Client.ToGqlString (toGqlQueryString)
import GraphQL.Client.Types (class GqlQuery, Client(..), class QueryClient, clientQuery, defQueryOpts, clientMutation, defMutationOpts)
import GraphQL.Client.Variables (class VarsTypeChecked, getVarsJson, getVarsTypeNames)
import Prim.Row as Row
import Simple.JSON as JSON
import Type.Data.List (Nil')
import Type.Proxy (Proxy(..))
......@@ -122,6 +125,7 @@ getClient (Session { token, backend: Backend b }) = createClient { headers, url:
queryGql
:: forall query returns
. GqlQuery Nil' OpQuery Schema query returns
-- => Row.Union Schema sr schema
=> JSON.ReadForeign returns
=> Session
-> String
......@@ -147,21 +151,24 @@ mutationGql session name q = do
-- Schema
type Schema =
{ annuaire_contacts :: { contact_id :: Int } -> Array AnnuaireContact
, context_ngrams :: { context_id :: Int, list_id :: Int } -> Array String
, contexts :: { context_id :: Int, node_id :: Int } -> Array GQLCTX.NodeContext
, contexts_for_ngrams :: { corpus_id :: Int, ngrams_terms :: GQLCTX.NgramsTerms, and_logic :: String } -> Array GQLCTX.Context
, imt_schools :: {} -> Array GQLIMT.School
{ annuaireContact :: { contactId :: Int } -> AnnuaireContact
, context :: { contextId :: Int, nodeId :: Int } -> GQLCTX.NodeContext
, contextsForNgrams :: { corpus_id :: Int, ngrams_terms :: GQLCTX.NgramsTerms, and_logic :: String } -> Array GQLCTX.Context
, corpus :: { id :: Int } -> GQLNode.Corpus
, languages :: {} -> Array GQLNLP.Language
, node_children :: { node_id :: Int, child_type :: NodeType } -> Array GQLNode.Node
, node_parent :: { node_id :: Int, parent_type :: NodeType } -> Array GQLNode.Node
, nodes :: { node_id :: Int } -> Array GQLNode.Node
, nodes_corpus :: { corpus_id :: Int } -> Array GQLNode.Corpus
, user_infos :: { user_id :: Int } -> Array UserInfo
, users :: { user_id :: Int } -> Array User
, ngramsForContextAndListId :: { contextId :: Int, listId :: Int } -> Array String
, node :: { id :: Int } -> GQLNode.Node
, nodes ::
{ parentId :: AsGql "Int" Int
, containsChildId :: AsGql "Int" Int
, deepChildId :: AsGql "Int" Int
, nodeType :: AsGql "NodeType" NodeType
}
-> Array GQLNode.Node
, schools :: {} -> Array GQLIMT.School
, team :: { team_node_id :: Int } -> Team
, tree :: { root_id :: Int } -> TreeFirstLevel
, tree_branch :: { node_id :: Int } -> BreadcrumbInfo
, user :: { id :: Int } -> User
, userInfo :: { userId :: Int } -> UserInfo
}
type Mutation =
......
......@@ -48,9 +48,9 @@ type AnnuaireContact =
}
type AnnuaireContactQuery =
{ annuaire_contacts ::
{ annuaireContact ::
Args
{ contact_id :: Var "id" Int }
{ contactId :: Var "id" Int }
{ ac_title :: Unit
, ac_source :: Unit
, ac_id :: Unit
......@@ -70,8 +70,8 @@ type AnnuaireContactQuery =
annuaireContactQuery :: AnnuaireContactQuery
annuaireContactQuery =
{ annuaire_contacts:
{ contact_id: Var :: _ "id" Int } =>>
{ annuaireContact:
{ contactId: Var :: _ "id" Int } =>>
GGQL.getFieldsStandard (Proxy :: _ AnnuaireContact)
}
......
......@@ -5,10 +5,11 @@ module Gargantext.Components.GraphQL.Context
, Hyperdata
, NodeContext
, NodeContext_
, nodeContextQuery
, ContextByIdAndNodeQuery
, getContextByIdAndNodeQuery
, NodeContextCategoryM
, contextsForNgramsQuery
, contextNgramsQuery
, getContextsForNgramsQuery
, getNgramsForContextAndListQuery
, NgramsTerms(..)
) where
......@@ -70,11 +71,11 @@ type NodeContext_ =
type NodeContext = Record NodeContext_
type NodeContextQuery =
{ contexts ::
type ContextByIdAndNodeQuery =
{ context ::
Args
{ context_id :: Var "context_id" Int
, node_id :: Var "node_id" Int
{ contextId :: Var "contextId" Int
, nodeId :: Var "nodeId" Int
}
{ nc_id :: Unit
, nc_node_id :: Unit
......@@ -84,17 +85,17 @@ type NodeContextQuery =
}
}
nodeContextQuery :: NodeContextQuery
nodeContextQuery =
{ contexts:
{ context_id: Var :: _ "context_id" Int
, node_id: Var :: _ "node_id" Int
getContextByIdAndNodeQuery :: ContextByIdAndNodeQuery
getContextByIdAndNodeQuery =
{ context:
{ contextId: Var :: _ "contextId" Int
, nodeId: Var :: _ "nodeId" Int
} =>>
GGQL.getFieldsStandard (Proxy :: _ NodeContext)
}
type ContextsForNgramsQuery =
{ contexts_for_ngrams ::
{ contextsForNgrams ::
Args
{ corpus_id :: Var "corpus_id" Int
, ngrams_terms :: Var "ngrams_terms" NgramsTerms
......@@ -131,9 +132,9 @@ type ContextsForNgramsQuery =
}
}
contextsForNgramsQuery :: ContextsForNgramsQuery
contextsForNgramsQuery =
{ contexts_for_ngrams:
getContextsForNgramsQuery :: ContextsForNgramsQuery
getContextsForNgramsQuery =
{ contextsForNgrams:
{ corpus_id: Var :: _ "corpus_id" Int
, ngrams_terms: Var :: _ "ngrams_terms" NgramsTerms
, and_logic: Var :: _ "and_logic" String
......@@ -141,20 +142,20 @@ contextsForNgramsQuery =
GGQL.getFieldsStandard (Proxy :: _ Context)
}
type ContextNgramsQuery =
{ context_ngrams ::
type NgramsForContextAndListQuery =
{ ngramsForContextAndListId ::
Args
{ context_id :: Var "context_id" Int
, list_id :: Var "list_id" Int
{ contextId :: Var "contextId" Int
, listId :: Var "listId" Int
}
Unit
}
contextNgramsQuery :: ContextNgramsQuery
contextNgramsQuery =
{ context_ngrams:
{ context_id: Var :: _ "context_id" Int
, list_id: Var :: _ "list_id" Int
getNgramsForContextAndListQuery :: NgramsForContextAndListQuery
getNgramsForContextAndListQuery =
{ ngramsForContextAndListId:
{ contextId: Var :: _ "contextId" Int
, listId: Var :: _ "listId" Int
} =>> unit
}
......
......@@ -11,15 +11,15 @@ type School =
}
type SchoolsQuery =
{ imt_schools ::
{ schools ::
{ school_id :: Unit
, school_longName :: Unit
, school_shortName :: Unit
}
}
schoolsQuery :: SchoolsQuery
schoolsQuery =
{ imt_schools:
getSchoolsQuery :: SchoolsQuery
getSchoolsQuery =
{ schools:
GGQL.getFieldsStandard (Proxy :: _ School)
}
module Gargantext.Components.GraphQL.Node where
import Data.Maybe (Maybe(..))
import Gargantext.Prelude
import Gargantext.Types (NodeType)
import Gargantext.Utils.GraphQL as GGQL
import Gargantext.Types (NodeType)
import GraphQL.Client.Args (Args, (=>>))
import GraphQL.Client.Alias ((:))
import GraphQL.Client.Args (Args, (=>>), OrArg(..), IgnoreArg(..))
import GraphQL.Client.Variable (Var(..))
import Type.Proxy (Proxy(..))
type Corpus =
{ id :: Int
, name :: String
, parent_id :: Int
, parent_id :: Maybe Int
, type_id :: Int
, node_type :: NodeType
}
......@@ -19,59 +21,88 @@ type Corpus =
type Node =
{ id :: Int
, name :: String
, parent_id :: Int
, parent_id :: Maybe Int
, type_id :: Int
, node_type :: NodeType
}
type NodesCorpusQuery =
{ nodes_corpus ::
Args
{ corpus_id :: Var "id" Int }
type NodeQ =
{ id :: Unit
, name :: Unit
, parent_id :: Unit
, type_id :: Unit
, node_type :: Unit
}
nodeQ :: NodeQ
nodeQ = GGQL.getFieldsStandard (Proxy :: _ Node)
type CorpusByIdQuery =
{ corpus ::
Args
{ id :: Var "id" Int }
NodeQ
}
type NodesQuery =
{ nodes ::
type NodeByIdQuery =
{ node ::
Args
{ node_id :: Var "id" Int }
{ id :: Unit
, name :: Unit
, parent_id :: Unit
, type_id :: Unit
, node_type :: Unit
{ id :: Var "id" Int }
NodeQ
}
getNodeByIdQuery :: NodeByIdQuery
getNodeByIdQuery =
{ node: { id: Var :: _ "id" Int } =>> nodeQ
}
nodesQuery :: NodesQuery
nodesQuery =
{ nodes: { node_id: Var :: _ "id" Int } =>>
GGQL.getFieldsStandard (Proxy :: _ Node)
type NodesQueryArgs =
{ parentId :: OrArg IgnoreArg Int
, containsChildId :: OrArg IgnoreArg Int
, nodeType :: OrArg IgnoreArg NodeType
}
nodesCorpusQuery :: NodesCorpusQuery
nodesCorpusQuery =
{ nodes_corpus: { corpus_id: Var :: _ "id" Int } =>>
type NodesQuery =
{ nodes :: Args NodesQueryArgs NodeQ }
getNodesQuery :: NodesQueryArgs -> NodesQuery
getNodesQuery args =
{ nodes: args =>> nodeQ }
-- getNodesQuery :: Maybe Int -> Maybe Int -> NodesQuery
-- getNodesQuery mParentId mChildId =
-- { nodes: { parentId: mVar mParentId
-- , containsChildId: mVar mChildId } =>>
-- -- , nodeType: Var :: _ "nodeType" (Maybe NodeType) } =>>
-- nodeQ
-- }
-- where
-- mVar Nothing = ArgL IgnoreArg
-- mVar (Just x) = ArgR x
getCorpusByIdQuery :: CorpusByIdQuery
getCorpusByIdQuery =
{ corpus: { id: Var :: _ "id" Int } =>>
GGQL.getFieldsStandard (Proxy :: _ Corpus)
}
nodeParentQuery =
{ node_parent:
{ node_id: Var :: _ "id" Int
, parent_type: Var :: _ "parent_type" NodeType
} =>>
GGQL.getFieldsStandard (Proxy :: _ Node)
getNodeParentQuery id nodeType =
{ parent:
nodes
:
{ containsChildId: id
, nodeType: nodeType
}
=>>
nodeQ
}
where
nodes = Proxy :: Proxy "nodes"
nodeChildrenQuery =
{ node_children:
{ node_id: Var :: _ "id" Int
, child_type: Var :: _ "child_type" NodeType
getNodeChildrenQuery =
{ nodes:
{ parentId: Var :: _ "id" Int
, nodeType: Var :: _ "nodeType" NodeType
} =>>
GGQL.getFieldsStandard (Proxy :: _ Node)
nodeQ
}
module Gargantext.Components.GraphQL.Tree where
import Data.Maybe (Maybe(..))
import Gargantext.Components.GraphQL.Node (Node, NodeQ, nodeQ, getNodeByIdQuery, getNodesQuery)
import Gargantext.Prelude
import Data.Maybe (Maybe)
import Gargantext.Routes (AppRoute)
import Gargantext.Types (NodeType)
import GraphQL.Client.Args ((=>>))
import Gargantext.Utils.GraphQL as GGQL
import GraphQL.Client.Alias ((:), Alias)
import GraphQL.Client.Args ((=>>), Args, OrArg(ArgR), IgnoreArg)
import GraphQL.Client.Variable (Var(..))
type TreeNode =
{ name :: String
, id :: Int
, node_type :: NodeType
, parent_id :: Maybe Int
}
import Type.Proxy (Proxy(..))
type TreeFirstLevel =
{ root :: TreeNode
, children :: Array TreeNode
, parent :: Maybe TreeNode
{ root :: Node
, children :: Array Node
, parent :: Maybe Node
}
type BreadcrumbInfo =
{ parents :: Array TreeNode }
{ parents :: Array Node }
treeFirstLevelQuery =
{ tree: { root_id: Var :: _ "id" Int } =>>
{ root:
{ name: unit
, node_type: unit
, id: unit
, parent_id: unit
-- | This is a composite query that is composed of calling "node" and
-- | "nodes" with appropriate arguments.
getTreeByRootIdQuery
:: Int
-> { root ::
Alias (Proxy "node")
( Args
{ id :: Int }
NodeQ
)
, children ::
Alias (Proxy "nodes")
( Args
{ parentId :: Int }
NodeQ
)
, parents ::
Alias (Proxy "nodes")
( Args
{ containsChildId :: Int }
NodeQ
)
}
getTreeByRootIdQuery id =
{ root:
node : { id: id } =>> nodeQ
, children:
{ name: unit
, node_type: unit
, id: unit
, parent_id: unit
}
, parent:
{ name: unit
, node_type: unit
, id: unit
, parent_id: unit
}
}
nodes : { parentId: id } =>> nodeQ
, parents:
nodes : { containsChildId: id } =>> nodeQ
}
where
node = Proxy :: Proxy "node"
nodes = Proxy :: Proxy "nodes"
breadcrumbQuery =
{ tree_branch: { node_id: Var :: _ "node_id" Int } =>>
{ parents:
{ name: unit
, node_type: unit
, id: unit
, parent_id: unit
}
breadcrumbQuery
:: Int
-> { parents ::
Alias (Proxy "nodes")
( Args
{ deepChildId :: Int }
NodeQ
)
}
breadcrumbQuery id =
{ parents:
nodes : { deepChildId: id } =>>
nodeQ
}
where
nodes = Proxy :: Proxy "nodes"
......@@ -47,8 +47,8 @@ type UserInfoM =
, ui_cwDescription :: String
}
userInfoQuery =
{ user_infos: { user_id: Var :: _ "id" Int } =>>
getUserInfoQuery =
{ userInfo: { userId: Var :: _ "id" Int } =>>
{ ui_id: unit
, ui_username: unit
, ui_email: unit
......@@ -178,8 +178,8 @@ showUser
showMUser u = maybe "" showUser u
userQuery =
{ users: { user_id: Var :: _ "id" Int } =>>
getUserByIdQuery =
{ user: { id: Var :: _ "id" Int } =>>
{ u_id: unit
, u_hyperdata:
{ shared:
......
......@@ -6,7 +6,7 @@ import Data.Maybe (Maybe(..), isJust)
import Data.Tuple.Nested ((/\))
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Corpus.Layout (layout)
import Gargantext.Components.GraphQL.Endpoints (getNode)
import Gargantext.Components.GraphQL.Endpoints (getNodeById)
import Gargantext.Config.REST (logRESTError)
import Gargantext.Hooks.Loader (useLoaderEffect)
import Gargantext.Hooks.Session (useSession)
......@@ -39,7 +39,7 @@ nodeCpt = here.component "node" cpt
let
errorHandler = logRESTError (R2.herePrefix here "[corpusLayout]")
loader { nodeId: nodeId_, session: session_ } = getNode session_ nodeId_
loader { nodeId: nodeId_, session: session_ } = getNodeById session_ nodeId_
-- | Hooks
-- |
......
......@@ -21,6 +21,7 @@ import Gargantext.Utils.Glyphicon (classNamePrefix, glyphiconToCharCode)
import Gargantext.Utils.SimpleJSON (encodeJsonArgonaut)
import GraphQL.Client.Args (class ArgGql)
import GraphQL.Client.GqlType (class GqlType)
import GraphQL.Client.ToGqlString (class GqlArgString)
import Prim.Row (class Union)
import Reactix as R
import Simple.JSON as JSON
......@@ -198,6 +199,8 @@ instance Argonaut.EncodeJson NodeType where
-- instance ArgGql String NodeType
-- instance ArgGql NodeType NodeType
instance GqlType NodeType "NodeType!"
instance GqlArgString NodeType where
toGqlArgStringImpl = show
instance Show NodeType where
show NodeUser = "NodeUser"
......
......@@ -5,12 +5,18 @@ module Gargantext.Utils.GraphQL
( class GetFieldsStandard
, PropGetFieldsStandard
, getFieldsStandard
, unwrapGraphQLResult
) where
import Prelude
import Data.Array as A
import Data.Bifunctor (rmap)
import Data.Either (Either(..), note)
import Data.HeytingAlgebra (class HeytingAlgebraRecord, tt)
import Data.Maybe (Maybe)
import Data.Tuple (Tuple(..))
import Gargantext.Config.REST (RESTError(CustomError))
import Heterogeneous.Mapping (class HMap, class Mapping, hmap)
import Prim.RowList (class RowToList)
import Type.Proxy (Proxy(..))
......@@ -54,3 +60,15 @@ instance propGetFieldsStandard ::
) =>
Mapping PropGetFieldsStandard t fields where
mapping PropGetFieldsStandard _ = getFieldsStandard (Proxy :: _ t)
-- | GraphQL returns an Either Error a result type and one usually has to get the head of a
unwrapGraphQLResult
:: forall a params
. (Show params)
=> Tuple String params
-> Either RESTError (Array a)
-> Either RESTError a
unwrapGraphQLResult _ (Left err) = Left err
unwrapGraphQLResult (Tuple name params) (Right res) =
note (CustomError $ "[unwrapGraphQLResult] " <> name <> " with params " <> show params <> " not found")
(A.head res)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment