[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 @@ ...@@ -1020,7 +1020,7 @@
"debouncing": "0.1.2", "debouncing": "0.1.2",
"graphql-client": { "graphql-client": {
"git": "https://github.com/OxfordAbstracts/purescript-graphql-client", "git": "https://github.com/OxfordAbstracts/purescript-graphql-client",
"ref": "v10.0.3", "ref": "694551e8baa992310eedf0a9d90f6e23b2e8d964",
"dependencies": [ "dependencies": [
"aff", "aff",
"affjax", "affjax",
...@@ -1780,7 +1780,7 @@ ...@@ -1780,7 +1780,7 @@
"graphql-client": { "graphql-client": {
"type": "git", "type": "git",
"url": "https://github.com/OxfordAbstracts/purescript-graphql-client", "url": "https://github.com/OxfordAbstracts/purescript-graphql-client",
"rev": "7f85c4d64ab4b767ecc999429c1c37f7a6ad4816", "rev": "694551e8baa992310eedf0a9d90f6e23b2e8d964",
"dependencies": [ "dependencies": [
"aff", "aff",
"affjax", "affjax",
......
...@@ -20,7 +20,8 @@ workspace: ...@@ -20,7 +20,8 @@ workspace:
# https://github.com/OxfordAbstracts/purescript-graphql-client/issues/138 # https://github.com/OxfordAbstracts/purescript-graphql-client/issues/138
graphql-client: graphql-client:
git: https://github.com/OxfordAbstracts/purescript-graphql-client git: https://github.com/OxfordAbstracts/purescript-graphql-client
ref: v10.0.3 ref: 694551e8baa992310eedf0a9d90f6e23b2e8d964
#ref: v10.0.3
dependencies: dependencies:
- aff - aff
- affjax - affjax
......
...@@ -17,7 +17,7 @@ import Gargantext.Components.Bootstrap as B ...@@ -17,7 +17,7 @@ import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), SpinnerTheme(..)) import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), SpinnerTheme(..))
import Gargantext.Components.Category (ratingSimpleLoader) import Gargantext.Components.Category (ratingSimpleLoader)
import Gargantext.Components.Document.Types (DocPath, Document(..), LoadedData, initialState) 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.NgramsTable.AutoSync (useAutoSync)
import Gargantext.Components.Node (NodePoly(..)) import Gargantext.Components.Node (NodePoly(..))
import Gargantext.Core.NgramsTable.Functions (addNewNgramA, applyNgramsPatches, coreDispatch, findNgramRoot, setTermListA, computeCache) import Gargantext.Core.NgramsTable.Functions (addNewNgramA, applyNgramsPatches, coreDispatch, findNgramRoot, setTermListA, computeCache)
...@@ -76,7 +76,7 @@ layoutCpt = R2.hereComponent here "layout" hCpt ...@@ -76,7 +76,7 @@ layoutCpt = R2.hereComponent here "layout" hCpt
useLoader useLoader
{ errorHandler: Nothing { errorHandler: Nothing
, herePrefix: hp , herePrefix: hp
, loader: \p -> getContextNgrams session p.contextId p.listId , loader: \p -> getNgramsForContextAndList session p.contextId p.listId
, path: { contextId: nodeId, listId } , path: { contextId: nodeId, listId }
, render: \contextNgrams -> , render: \contextNgrams ->
layoutWithContextNgrams $ Record.merge props { contextNgrams } layoutWithContextNgrams $ Record.merge props { contextNgrams }
......
...@@ -6,6 +6,7 @@ import DOM.Simple (window) ...@@ -6,6 +6,7 @@ import DOM.Simple (window)
import Data.Array as A import Data.Array as A
import Data.Maybe (Maybe(..), fromMaybe) import Data.Maybe (Maybe(..), fromMaybe)
import Data.Traversable (traverse_) import Data.Traversable (traverse_)
import Effect (Effect)
import Effect.Aff (Aff) import Effect.Aff (Aff)
import Effect.Class (liftEffect) import Effect.Class (liftEffect)
import Gargantext.AsyncTasks as GAT import Gargantext.AsyncTasks as GAT
...@@ -27,12 +28,12 @@ import Gargantext.Components.Forest.Tree.Node.Action.Update (updateRequest) ...@@ -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.Action.Upload (uploadArbitraryFile, uploadFile)
import Gargantext.Components.Forest.Tree.Node.Box (nodePopupView) import Gargantext.Components.Forest.Tree.Node.Box (nodePopupView)
import Gargantext.Components.Forest.Tree.Node.Tools.SubTree.Types (SubTreeOut(..)) 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.Node (Node)
import Gargantext.Components.GraphQL.Tree (TreeFirstLevel, TreeNode) import Gargantext.Components.GraphQL.Tree (TreeFirstLevel)
import Gargantext.Config.REST (AffRESTError) import Gargantext.Config.REST (AffRESTError)
import Gargantext.Config.Utils (handleRESTError) import Gargantext.Config.Utils (handleRESTError)
import Gargantext.Hooks.LinkHandler (useLinkHandler) import Gargantext.Hooks.LinkHandler (useLinkHandler, Methods)
import Gargantext.Hooks.Loader (useLoader) import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes (AppRoute(Home), appPath, nodeTypeAppRoute) import Gargantext.Routes (AppRoute(Home), appPath, nodeTypeAppRoute)
import Gargantext.Sessions (Session(..), sessionId) import Gargantext.Sessions (Session(..), sessionId)
...@@ -101,10 +102,10 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt ...@@ -101,10 +102,10 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt
$ parent $ parent
<> childrenEl <> childrenEl
makeFolderElements :: Array TreeNode -> Record FolderViewProps -> Array R.Element makeFolderElements :: Array Node -> Record FolderViewProps -> Array R.Element
makeFolderElements folders' props = makeFolderElementsMap <$> folders' makeFolderElements folders' props = makeFolderElementsMap <$> folders'
where where
makeFolderElementsMap :: TreeNode -> R.Element makeFolderElementsMap :: Node -> R.Element
makeFolderElementsMap node = folder makeFolderElementsMap node = folder
{ nodeId: node.id { nodeId: node.id
, linkId: node.id , linkId: node.id
...@@ -117,7 +118,7 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt ...@@ -117,7 +118,7 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt
, text: node.name , 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 = makeParentFolder root (Just parent) props =
[ folder [ folder
{ linkId: parent.id { linkId: parent.id
...@@ -133,7 +134,7 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt ...@@ -133,7 +134,7 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt
] ]
makeParentFolder _ Nothing _ = [] makeParentFolder _ Nothing _ = []
sortFolders :: TreeNode -> TreeNode -> Ordering sortFolders :: Node -> Node -> Ordering
sortFolders a b = compare a.id b.id sortFolders a b = compare a.id b.id
type FolderProps = type FolderProps =
...@@ -298,7 +299,9 @@ backButtonSmartMainCpt = here.component "backButtonSmartMain" cpt ...@@ -298,7 +299,9 @@ backButtonSmartMainCpt = here.component "backButtonSmartMain" cpt
[ H.i { className: "fa fa-arrow-left", title: "Previous view" } [] [ H.i { className: "fa fa-arrow-left", title: "Previous view" } []
] ]
where 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 | rootId == pId = handlers.goToRoute Home
| otherwise = handlers.goToPreviousPage unit | otherwise = handlers.goToPreviousPage unit
...@@ -315,7 +318,7 @@ loadFolders :: Record LoadProps -> AffRESTError TreeFirstLevel ...@@ -315,7 +318,7 @@ loadFolders :: Record LoadProps -> AffRESTError TreeFirstLevel
loadFolders { nodeId, session } = getTreeFirstLevel session nodeId loadFolders { nodeId, session } = getTreeFirstLevel session nodeId
loadNode :: Record LoadProps -> AffRESTError Node loadNode :: Record LoadProps -> AffRESTError Node
loadNode { nodeId, session } = getNode session nodeId loadNode { nodeId, session } = getNodeById session nodeId
type PerformActionProps = type PerformActionProps =
( boxes :: Boxes ( boxes :: Boxes
......
...@@ -11,7 +11,8 @@ import Data.String (Pattern(..), split) ...@@ -11,7 +11,8 @@ import Data.String (Pattern(..), split)
import Gargantext.Components.App.Store as Store import Gargantext.Components.App.Store as Store
import Gargantext.Components.Bootstrap as B import Gargantext.Components.Bootstrap as B
import Gargantext.Components.GraphQL.Endpoints (getBreadcrumb, getNodeChildren, getNodeParent) 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.Config.REST (AffRESTError)
import Gargantext.Ends (Backend(..)) import Gargantext.Ends (Backend(..))
import Gargantext.Hooks.Loader (useLoader) import Gargantext.Hooks.Loader (useLoader)
...@@ -195,10 +196,10 @@ breadcrumbViewMainCpt = here.component "breadcrumbViewMainCpt" cpt ...@@ -195,10 +196,10 @@ breadcrumbViewMainCpt = here.component "breadcrumbViewMainCpt" cpt
pure $ pure $
R.fragment items 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' makeBreadcrumbElements items' session format openTreeNodes = makeBreadcrumbElementsMap <$> items'
where where
makeBreadcrumbElementsMap :: TreeNode -> R.Element makeBreadcrumbElementsMap :: Node -> R.Element
makeBreadcrumbElementsMap node = breadcrumbItem makeBreadcrumbElementsMap node = breadcrumbItem
{ linkId: node.id { linkId: node.id
, linkNodeType: node.node_type , linkNodeType: node.node_type
...@@ -353,8 +354,8 @@ loadBreadcrumbData { route: CorpusDocument _s corpusId listId documentId, sessio ...@@ -353,8 +354,8 @@ loadBreadcrumbData { route: CorpusDocument _s corpusId listId documentId, sessio
loadBreadcrumbData { route: Dashboard _s nodeId, session } = do loadBreadcrumbData { route: Dashboard _s nodeId, session } = do
loadBreadcrumbDataRaw { nodeId, session } loadBreadcrumbDataRaw { nodeId, session }
loadBreadcrumbData { route: Document _s listId documentId, session } = do loadBreadcrumbData { route: Document _s listId documentId, session } = do
corpora <- getNodeParent session listId GT.Corpus corpus <- getNodeParent session listId GT.Corpus
let nodeId = maybe listId _.id $ either (const Nothing) A.head corpora let nodeId = either (const listId) _.id corpus
loadBreadcrumbDataRaw { nodeId, session } loadBreadcrumbDataRaw { nodeId, session }
loadBreadcrumbData { route: Folder _s nodeId, session } = do loadBreadcrumbData { route: Folder _s nodeId, session } = do
loadBreadcrumbDataRaw { nodeId, session } loadBreadcrumbDataRaw { nodeId, session }
......
...@@ -260,16 +260,17 @@ nodeSpanCpt = here.component "nodeSpan" cpt ...@@ -260,16 +260,17 @@ nodeSpanCpt = here.component "nodeSpan" cpt
NT.NUpdateWorkerProgress ji atl -> do NT.NUpdateWorkerProgress ji atl -> do
-- TODO Fire this only once! -- TODO Fire this only once!
here.log3 "[nodeSpan] update job progress" ji atl here.log3 "[nodeSpan] update job progress" ji atl
let wtl = GT.WorkerTaskWithLog { task: ji, lastLog: Just atl }
if GT.asyncTaskLogIsFinished atl then do if GT.asyncTaskLogIsFinished atl then do
-- Handle error but only when the task is not already in the storage -- 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). -- (we want to avoid reporting the error multiple times, from different places).
-- See e.g. https://gitlab.iscpif.fr/gargantext/purescript-gargantext/issues/728 -- See e.g. https://gitlab.iscpif.fr/gargantext/purescript-gargantext/issues/728
-- (error is thrown before the task marks any progress) -- (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 unless hasTask $ do
handleErrorInAsyncTaskLog boxes.errors atl handleErrorInAsyncTaskLog boxes.errors atl
else do else do
GAT.insert props.id ji boxes.tasks GAT.insert props.id wtl boxes.tasks
_ -> pure unit _ -> pure unit
ws <- T.read boxes.wsNotification ws <- T.read boxes.wsNotification
let action = NT.InsertCallback (NT.UpdateTree props.id) ("node-span-" <> show props.id) cb let action = NT.InsertCallback (NT.UpdateTree props.id) ("node-span-" <> show props.id) cb
......
...@@ -25,6 +25,8 @@ import Gargantext.Routes (AppRoute) ...@@ -25,6 +25,8 @@ import Gargantext.Routes (AppRoute)
import Gargantext.Sessions (Session(..)) import Gargantext.Sessions (Session(..))
import Gargantext.Types (NodeType) import Gargantext.Types (NodeType)
import Gargantext.Utils.Reactix as R2 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.BaseClients.Urql (UrqlClient, createClient)
import GraphQL.Client.Operation (OpMutation, OpQuery) import GraphQL.Client.Operation (OpMutation, OpQuery)
import GraphQL.Client.Query (decodeGqlRes) --, mutationJson) import GraphQL.Client.Query (decodeGqlRes) --, mutationJson)
...@@ -32,6 +34,7 @@ import GraphQL.Client.SafeQueryName (safeQueryName) ...@@ -32,6 +34,7 @@ import GraphQL.Client.SafeQueryName (safeQueryName)
import GraphQL.Client.ToGqlString (toGqlQueryString) import GraphQL.Client.ToGqlString (toGqlQueryString)
import GraphQL.Client.Types (class GqlQuery, Client(..), class QueryClient, clientQuery, defQueryOpts, clientMutation, defMutationOpts) import GraphQL.Client.Types (class GqlQuery, Client(..), class QueryClient, clientQuery, defQueryOpts, clientMutation, defMutationOpts)
import GraphQL.Client.Variables (class VarsTypeChecked, getVarsJson, getVarsTypeNames) import GraphQL.Client.Variables (class VarsTypeChecked, getVarsJson, getVarsTypeNames)
import Prim.Row as Row
import Simple.JSON as JSON import Simple.JSON as JSON
import Type.Data.List (Nil') import Type.Data.List (Nil')
import Type.Proxy (Proxy(..)) import Type.Proxy (Proxy(..))
...@@ -122,6 +125,7 @@ getClient (Session { token, backend: Backend b }) = createClient { headers, url: ...@@ -122,6 +125,7 @@ getClient (Session { token, backend: Backend b }) = createClient { headers, url:
queryGql queryGql
:: forall query returns :: forall query returns
. GqlQuery Nil' OpQuery Schema query returns . GqlQuery Nil' OpQuery Schema query returns
-- => Row.Union Schema sr schema
=> JSON.ReadForeign returns => JSON.ReadForeign returns
=> Session => Session
-> String -> String
...@@ -147,21 +151,24 @@ mutationGql session name q = do ...@@ -147,21 +151,24 @@ mutationGql session name q = do
-- Schema -- Schema
type Schema = type Schema =
{ annuaire_contacts :: { contact_id :: Int } -> Array AnnuaireContact { annuaireContact :: { contactId :: Int } -> AnnuaireContact
, context_ngrams :: { context_id :: Int, list_id :: Int } -> Array String , context :: { contextId :: Int, nodeId :: Int } -> GQLCTX.NodeContext
, contexts :: { context_id :: Int, node_id :: Int } -> Array GQLCTX.NodeContext , contextsForNgrams :: { corpus_id :: Int, ngrams_terms :: GQLCTX.NgramsTerms, and_logic :: String } -> Array GQLCTX.Context
, contexts_for_ngrams :: { corpus_id :: Int, ngrams_terms :: GQLCTX.NgramsTerms, and_logic :: String } -> Array GQLCTX.Context , corpus :: { id :: Int } -> GQLNode.Corpus
, imt_schools :: {} -> Array GQLIMT.School
, languages :: {} -> Array GQLNLP.Language , languages :: {} -> Array GQLNLP.Language
, node_children :: { node_id :: Int, child_type :: NodeType } -> Array GQLNode.Node , ngramsForContextAndListId :: { contextId :: Int, listId :: Int } -> Array String
, node_parent :: { node_id :: Int, parent_type :: NodeType } -> Array GQLNode.Node , node :: { id :: Int } -> GQLNode.Node
, nodes :: { node_id :: Int } -> Array GQLNode.Node , nodes ::
, nodes_corpus :: { corpus_id :: Int } -> Array GQLNode.Corpus { parentId :: AsGql "Int" Int
, user_infos :: { user_id :: Int } -> Array UserInfo , containsChildId :: AsGql "Int" Int
, users :: { user_id :: Int } -> Array User , deepChildId :: AsGql "Int" Int
, nodeType :: AsGql "NodeType" NodeType
}
-> Array GQLNode.Node
, schools :: {} -> Array GQLIMT.School
, team :: { team_node_id :: Int } -> Team , team :: { team_node_id :: Int } -> Team
, tree :: { root_id :: Int } -> TreeFirstLevel , user :: { id :: Int } -> User
, tree_branch :: { node_id :: Int } -> BreadcrumbInfo , userInfo :: { userId :: Int } -> UserInfo
} }
type Mutation = type Mutation =
......
...@@ -48,9 +48,9 @@ type AnnuaireContact = ...@@ -48,9 +48,9 @@ type AnnuaireContact =
} }
type AnnuaireContactQuery = type AnnuaireContactQuery =
{ annuaire_contacts :: { annuaireContact ::
Args Args
{ contact_id :: Var "id" Int } { contactId :: Var "id" Int }
{ ac_title :: Unit { ac_title :: Unit
, ac_source :: Unit , ac_source :: Unit
, ac_id :: Unit , ac_id :: Unit
...@@ -70,8 +70,8 @@ type AnnuaireContactQuery = ...@@ -70,8 +70,8 @@ type AnnuaireContactQuery =
annuaireContactQuery :: AnnuaireContactQuery annuaireContactQuery :: AnnuaireContactQuery
annuaireContactQuery = annuaireContactQuery =
{ annuaire_contacts: { annuaireContact:
{ contact_id: Var :: _ "id" Int } =>> { contactId: Var :: _ "id" Int } =>>
GGQL.getFieldsStandard (Proxy :: _ AnnuaireContact) GGQL.getFieldsStandard (Proxy :: _ AnnuaireContact)
} }
......
...@@ -5,10 +5,11 @@ module Gargantext.Components.GraphQL.Context ...@@ -5,10 +5,11 @@ module Gargantext.Components.GraphQL.Context
, Hyperdata , Hyperdata
, NodeContext , NodeContext
, NodeContext_ , NodeContext_
, nodeContextQuery , ContextByIdAndNodeQuery
, getContextByIdAndNodeQuery
, NodeContextCategoryM , NodeContextCategoryM
, contextsForNgramsQuery , getContextsForNgramsQuery
, contextNgramsQuery , getNgramsForContextAndListQuery
, NgramsTerms(..) , NgramsTerms(..)
) where ) where
...@@ -70,11 +71,11 @@ type NodeContext_ = ...@@ -70,11 +71,11 @@ type NodeContext_ =
type NodeContext = Record NodeContext_ type NodeContext = Record NodeContext_
type NodeContextQuery = type ContextByIdAndNodeQuery =
{ contexts :: { context ::
Args Args
{ context_id :: Var "context_id" Int { contextId :: Var "contextId" Int
, node_id :: Var "node_id" Int , nodeId :: Var "nodeId" Int
} }
{ nc_id :: Unit { nc_id :: Unit
, nc_node_id :: Unit , nc_node_id :: Unit
...@@ -84,17 +85,17 @@ type NodeContextQuery = ...@@ -84,17 +85,17 @@ type NodeContextQuery =
} }
} }
nodeContextQuery :: NodeContextQuery getContextByIdAndNodeQuery :: ContextByIdAndNodeQuery
nodeContextQuery = getContextByIdAndNodeQuery =
{ contexts: { context:
{ context_id: Var :: _ "context_id" Int { contextId: Var :: _ "contextId" Int
, node_id: Var :: _ "node_id" Int , nodeId: Var :: _ "nodeId" Int
} =>> } =>>
GGQL.getFieldsStandard (Proxy :: _ NodeContext) GGQL.getFieldsStandard (Proxy :: _ NodeContext)
} }
type ContextsForNgramsQuery = type ContextsForNgramsQuery =
{ contexts_for_ngrams :: { contextsForNgrams ::
Args Args
{ corpus_id :: Var "corpus_id" Int { corpus_id :: Var "corpus_id" Int
, ngrams_terms :: Var "ngrams_terms" NgramsTerms , ngrams_terms :: Var "ngrams_terms" NgramsTerms
...@@ -131,9 +132,9 @@ type ContextsForNgramsQuery = ...@@ -131,9 +132,9 @@ type ContextsForNgramsQuery =
} }
} }
contextsForNgramsQuery :: ContextsForNgramsQuery getContextsForNgramsQuery :: ContextsForNgramsQuery
contextsForNgramsQuery = getContextsForNgramsQuery =
{ contexts_for_ngrams: { contextsForNgrams:
{ corpus_id: Var :: _ "corpus_id" Int { corpus_id: Var :: _ "corpus_id" Int
, ngrams_terms: Var :: _ "ngrams_terms" NgramsTerms , ngrams_terms: Var :: _ "ngrams_terms" NgramsTerms
, and_logic: Var :: _ "and_logic" String , and_logic: Var :: _ "and_logic" String
...@@ -141,20 +142,20 @@ contextsForNgramsQuery = ...@@ -141,20 +142,20 @@ contextsForNgramsQuery =
GGQL.getFieldsStandard (Proxy :: _ Context) GGQL.getFieldsStandard (Proxy :: _ Context)
} }
type ContextNgramsQuery = type NgramsForContextAndListQuery =
{ context_ngrams :: { ngramsForContextAndListId ::
Args Args
{ context_id :: Var "context_id" Int { contextId :: Var "contextId" Int
, list_id :: Var "list_id" Int , listId :: Var "listId" Int
} }
Unit Unit
} }
contextNgramsQuery :: ContextNgramsQuery getNgramsForContextAndListQuery :: NgramsForContextAndListQuery
contextNgramsQuery = getNgramsForContextAndListQuery =
{ context_ngrams: { ngramsForContextAndListId:
{ context_id: Var :: _ "context_id" Int { contextId: Var :: _ "contextId" Int
, list_id: Var :: _ "list_id" Int , listId: Var :: _ "listId" Int
} =>> unit } =>> unit
} }
......
...@@ -11,15 +11,15 @@ type School = ...@@ -11,15 +11,15 @@ type School =
} }
type SchoolsQuery = type SchoolsQuery =
{ imt_schools :: { schools ::
{ school_id :: Unit { school_id :: Unit
, school_longName :: Unit , school_longName :: Unit
, school_shortName :: Unit , school_shortName :: Unit
} }
} }
schoolsQuery :: SchoolsQuery getSchoolsQuery :: SchoolsQuery
schoolsQuery = getSchoolsQuery =
{ imt_schools: { schools:
GGQL.getFieldsStandard (Proxy :: _ School) GGQL.getFieldsStandard (Proxy :: _ School)
} }
module Gargantext.Components.GraphQL.Node where module Gargantext.Components.GraphQL.Node where
import Data.Maybe (Maybe(..))
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Types (NodeType) import Gargantext.Types (NodeType)
import Gargantext.Utils.GraphQL as GGQL import Gargantext.Utils.GraphQL as GGQL
import Gargantext.Types (NodeType) 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 GraphQL.Client.Variable (Var(..))
import Type.Proxy (Proxy(..)) import Type.Proxy (Proxy(..))
type Corpus = type Corpus =
{ id :: Int { id :: Int
, name :: String , name :: String
, parent_id :: Int , parent_id :: Maybe Int
, type_id :: Int , type_id :: Int
, node_type :: NodeType , node_type :: NodeType
} }
...@@ -19,59 +21,88 @@ type Corpus = ...@@ -19,59 +21,88 @@ type Corpus =
type Node = type Node =
{ id :: Int { id :: Int
, name :: String , name :: String
, parent_id :: Int , parent_id :: Maybe Int
, type_id :: Int , type_id :: Int
, node_type :: NodeType , node_type :: NodeType
} }
type NodesCorpusQuery = type NodeQ =
{ nodes_corpus :: { id :: Unit
, name :: Unit
, parent_id :: Unit
, type_id :: Unit
, node_type :: Unit
}
nodeQ :: NodeQ
nodeQ = GGQL.getFieldsStandard (Proxy :: _ Node)
type CorpusByIdQuery =
{ corpus ::
Args Args
{ corpus_id :: Var "id" Int } { id :: Var "id" Int }
{ id :: Unit NodeQ
, name :: Unit
, parent_id :: Unit
, type_id :: Unit
, node_type :: Unit
}
} }
type NodesQuery = type NodeByIdQuery =
{ nodes :: { node ::
Args Args
{ node_id :: Var "id" Int } { id :: Var "id" Int }
{ id :: Unit NodeQ
, name :: Unit }
, parent_id :: Unit
, type_id :: Unit getNodeByIdQuery :: NodeByIdQuery
, node_type :: Unit getNodeByIdQuery =
} { node: { id: Var :: _ "id" Int } =>> nodeQ
} }
nodesQuery :: NodesQuery type NodesQueryArgs =
nodesQuery = { parentId :: OrArg IgnoreArg Int
{ nodes: { node_id: Var :: _ "id" Int } =>> , containsChildId :: OrArg IgnoreArg Int
GGQL.getFieldsStandard (Proxy :: _ Node) , nodeType :: OrArg IgnoreArg NodeType
} }
nodesCorpusQuery :: NodesCorpusQuery type NodesQuery =
nodesCorpusQuery = { nodes :: Args NodesQueryArgs NodeQ }
{ nodes_corpus: { corpus_id: Var :: _ "id" Int } =>>
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) GGQL.getFieldsStandard (Proxy :: _ Corpus)
} }
nodeParentQuery = getNodeParentQuery id nodeType =
{ node_parent: { parent:
{ node_id: Var :: _ "id" Int nodes
, parent_type: Var :: _ "parent_type" NodeType :
} =>> { containsChildId: id
GGQL.getFieldsStandard (Proxy :: _ Node) , nodeType: nodeType
}
=>>
nodeQ
} }
where
nodes = Proxy :: Proxy "nodes"
nodeChildrenQuery = getNodeChildrenQuery =
{ node_children: { nodes:
{ node_id: Var :: _ "id" Int { parentId: Var :: _ "id" Int
, child_type: Var :: _ "child_type" NodeType , nodeType: Var :: _ "nodeType" NodeType
} =>> } =>>
GGQL.getFieldsStandard (Proxy :: _ Node) nodeQ
} }
module Gargantext.Components.GraphQL.Tree where module Gargantext.Components.GraphQL.Tree where
import Data.Maybe (Maybe(..))
import Gargantext.Components.GraphQL.Node (Node, NodeQ, nodeQ, getNodeByIdQuery, getNodesQuery)
import Gargantext.Prelude import Gargantext.Prelude
import Data.Maybe (Maybe)
import Gargantext.Routes (AppRoute) import Gargantext.Routes (AppRoute)
import Gargantext.Types (NodeType) 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(..)) import GraphQL.Client.Variable (Var(..))
import Type.Proxy (Proxy(..))
type TreeNode =
{ name :: String
, id :: Int
, node_type :: NodeType
, parent_id :: Maybe Int
}
type TreeFirstLevel = type TreeFirstLevel =
{ root :: TreeNode { root :: Node
, children :: Array TreeNode , children :: Array Node
, parent :: Maybe TreeNode , parent :: Maybe Node
} }
type BreadcrumbInfo = type BreadcrumbInfo =
{ parents :: Array TreeNode } { parents :: Array Node }
treeFirstLevelQuery = -- | This is a composite query that is composed of calling "node" and
{ tree: { root_id: Var :: _ "id" Int } =>> -- | "nodes" with appropriate arguments.
{ root: getTreeByRootIdQuery
{ name: unit :: Int
, node_type: unit -> { root ::
, id: unit Alias (Proxy "node")
, parent_id: unit ( Args
} { id :: Int }
, children: NodeQ
{ name: unit )
, node_type: unit , children ::
, id: unit Alias (Proxy "nodes")
, parent_id: unit ( Args
} { parentId :: Int }
, parent: NodeQ
{ name: unit )
, node_type: unit , parents ::
, id: unit Alias (Proxy "nodes")
, parent_id: unit ( Args
} { containsChildId :: Int }
} NodeQ
)
}
getTreeByRootIdQuery id =
{ root:
node : { id: id } =>> nodeQ
, children:
nodes : { parentId: id } =>> nodeQ
, parents:
nodes : { containsChildId: id } =>> nodeQ
} }
where
node = Proxy :: Proxy "node"
nodes = Proxy :: Proxy "nodes"
breadcrumbQuery = breadcrumbQuery
{ tree_branch: { node_id: Var :: _ "node_id" Int } =>> :: Int
{ parents: -> { parents ::
{ name: unit Alias (Proxy "nodes")
, node_type: unit ( Args
, id: unit { deepChildId :: Int }
, parent_id: unit NodeQ
} )
} }
breadcrumbQuery id =
{ parents:
nodes : { deepChildId: id } =>>
nodeQ
} }
where
nodes = Proxy :: Proxy "nodes"
...@@ -47,8 +47,8 @@ type UserInfoM = ...@@ -47,8 +47,8 @@ type UserInfoM =
, ui_cwDescription :: String , ui_cwDescription :: String
} }
userInfoQuery = getUserInfoQuery =
{ user_infos: { user_id: Var :: _ "id" Int } =>> { userInfo: { userId: Var :: _ "id" Int } =>>
{ ui_id: unit { ui_id: unit
, ui_username: unit , ui_username: unit
, ui_email: unit , ui_email: unit
...@@ -178,8 +178,8 @@ showUser ...@@ -178,8 +178,8 @@ showUser
showMUser u = maybe "" showUser u showMUser u = maybe "" showUser u
userQuery = getUserByIdQuery =
{ users: { user_id: Var :: _ "id" Int } =>> { user: { id: Var :: _ "id" Int } =>>
{ u_id: unit { u_id: unit
, u_hyperdata: , u_hyperdata:
{ shared: { shared:
......
...@@ -6,7 +6,7 @@ import Data.Maybe (Maybe(..), isJust) ...@@ -6,7 +6,7 @@ import Data.Maybe (Maybe(..), isJust)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Gargantext.Components.Bootstrap as B import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Corpus.Layout (layout) 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.Config.REST (logRESTError)
import Gargantext.Hooks.Loader (useLoaderEffect) import Gargantext.Hooks.Loader (useLoaderEffect)
import Gargantext.Hooks.Session (useSession) import Gargantext.Hooks.Session (useSession)
...@@ -39,7 +39,7 @@ nodeCpt = here.component "node" cpt ...@@ -39,7 +39,7 @@ nodeCpt = here.component "node" cpt
let let
errorHandler = logRESTError (R2.herePrefix here "[corpusLayout]") errorHandler = logRESTError (R2.herePrefix here "[corpusLayout]")
loader { nodeId: nodeId_, session: session_ } = getNode session_ nodeId_ loader { nodeId: nodeId_, session: session_ } = getNodeById session_ nodeId_
-- | Hooks -- | Hooks
-- | -- |
......
...@@ -21,6 +21,7 @@ import Gargantext.Utils.Glyphicon (classNamePrefix, glyphiconToCharCode) ...@@ -21,6 +21,7 @@ import Gargantext.Utils.Glyphicon (classNamePrefix, glyphiconToCharCode)
import Gargantext.Utils.SimpleJSON (encodeJsonArgonaut) import Gargantext.Utils.SimpleJSON (encodeJsonArgonaut)
import GraphQL.Client.Args (class ArgGql) import GraphQL.Client.Args (class ArgGql)
import GraphQL.Client.GqlType (class GqlType) import GraphQL.Client.GqlType (class GqlType)
import GraphQL.Client.ToGqlString (class GqlArgString)
import Prim.Row (class Union) import Prim.Row (class Union)
import Reactix as R import Reactix as R
import Simple.JSON as JSON import Simple.JSON as JSON
...@@ -198,6 +199,8 @@ instance Argonaut.EncodeJson NodeType where ...@@ -198,6 +199,8 @@ instance Argonaut.EncodeJson NodeType where
-- instance ArgGql String NodeType -- instance ArgGql String NodeType
-- instance ArgGql NodeType NodeType -- instance ArgGql NodeType NodeType
instance GqlType NodeType "NodeType!" instance GqlType NodeType "NodeType!"
instance GqlArgString NodeType where
toGqlArgStringImpl = show
instance Show NodeType where instance Show NodeType where
show NodeUser = "NodeUser" show NodeUser = "NodeUser"
......
...@@ -5,12 +5,18 @@ module Gargantext.Utils.GraphQL ...@@ -5,12 +5,18 @@ module Gargantext.Utils.GraphQL
( class GetFieldsStandard ( class GetFieldsStandard
, PropGetFieldsStandard , PropGetFieldsStandard
, getFieldsStandard , getFieldsStandard
, unwrapGraphQLResult
) where ) where
import Prelude import Prelude
import Data.Array as A
import Data.Bifunctor (rmap)
import Data.Either (Either(..), note)
import Data.HeytingAlgebra (class HeytingAlgebraRecord, tt) import Data.HeytingAlgebra (class HeytingAlgebraRecord, tt)
import Data.Maybe (Maybe) import Data.Maybe (Maybe)
import Data.Tuple (Tuple(..))
import Gargantext.Config.REST (RESTError(CustomError))
import Heterogeneous.Mapping (class HMap, class Mapping, hmap) import Heterogeneous.Mapping (class HMap, class Mapping, hmap)
import Prim.RowList (class RowToList) import Prim.RowList (class RowToList)
import Type.Proxy (Proxy(..)) import Type.Proxy (Proxy(..))
...@@ -54,3 +60,15 @@ instance propGetFieldsStandard :: ...@@ -54,3 +60,15 @@ instance propGetFieldsStandard ::
) => ) =>
Mapping PropGetFieldsStandard t fields where Mapping PropGetFieldsStandard t fields where
mapping PropGetFieldsStandard _ = getFieldsStandard (Proxy :: _ t) 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