diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 9411810a5cc8b8bdc0d3af714c1e2cc9a686a2ff..d2fa1b8a283d96276ced7f99192e9b2110c9776a 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -21,5 +21,10 @@ * [Create a connector](for-developers/gateway/connector/create-a-connector.md) * [Parsing response with JSONdata](for-developers/connector/Parsing-response-with-JSONata.md) * [Frontend](for-developers/frontend/README.md) - * [Update GraphQL Queries](for-developers/frontend/Update-queries-GrahpQL-in-the-frontend.md) - * [📊 Visualisations](for-developers/frontend/visualisations.md) + * [GraphQL](for-developers/frontend/graphql/README.md) + * [Unions and interfaces](for-developers/frontend/graphql/unions-and-interfaces.md) + * [Update GraphQL Queries](for-developers/frontend/graphql/update-queries-grahpql-in-the-frontend.md) + * [📖 Storybook](for-developers/frontend/visualisations.md) +* [👩🳠Recipes](for-developers/recipes/README.md) + * [🚧 Add a visualization](for-developers/recipes/add-a-visualization.md) + * [Add an algorithm handler on Exareme](for-developers/recipes/add-an-algorithm-handler-on-exareme.md) diff --git a/docs/for-developers/frontend/graphql/README.md b/docs/for-developers/frontend/graphql/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8c5b682092b4d3c5932143fa6bb8934aea2630b8 --- /dev/null +++ b/docs/for-developers/frontend/graphql/README.md @@ -0,0 +1,2 @@ +# GraphQL + diff --git a/docs/for-developers/frontend/graphql/unions-and-interfaces.md b/docs/for-developers/frontend/graphql/unions-and-interfaces.md new file mode 100644 index 0000000000000000000000000000000000000000..2d03765f996b1c6201df4f65ccb68899ef176c8d --- /dev/null +++ b/docs/for-developers/frontend/graphql/unions-and-interfaces.md @@ -0,0 +1,16 @@ +--- +description: Abstract schema types +--- + +# Unions and interfaces + +**Unions** and **interfaces** are abstract GraphQL types that enable a schema field to return one of multiple object types. + +Read more about [unions and interface](https://www.apollographql.com/docs/apollo-server/schema/unions-interfaces/). + +In order to be correctly interpreted in the Frontend, especially when dealing [with fragments](https://github.com/apollographql/apollo-client/issues/7050), we have to provide to the cache the possible types for a fragment.  + +{% hint style="warning" %} +In the file `cache.tsx`, within the parameter `possiblesTypes` you should provide a list of types that you expect to see in the GraphQL responses, if a type is missing this will result in a empty response for the specific type missing.  +{% endhint %} + diff --git a/docs/for-developers/frontend/Update-queries-GrahpQL-in-the-frontend.md b/docs/for-developers/frontend/graphql/update-queries-grahpql-in-the-frontend.md similarity index 100% rename from docs/for-developers/frontend/Update-queries-GrahpQL-in-the-frontend.md rename to docs/for-developers/frontend/graphql/update-queries-grahpql-in-the-frontend.md diff --git a/docs/for-developers/frontend/visualisations.md b/docs/for-developers/frontend/visualisations.md index 3b6e066e2afadcce097be8c10bba2aa5b321a7b0..ba489645d4f6924bed01aa25c03f4042cd4ab90e 100644 --- a/docs/for-developers/frontend/visualisations.md +++ b/docs/for-developers/frontend/visualisations.md @@ -1,4 +1,4 @@ -# 📊 Visualisations +# 📖 Storybook To see the different possible visualisations in the frontend we have integrated [storybook.js](https://storybook.js.org/) directly in the frontend. diff --git a/docs/for-developers/gateway/connector/create-a-connector.md b/docs/for-developers/gateway/connector/create-a-connector.md index fd80f3ae2ea89904be43cfadb7303c2b3e52a7ca..71c907536dd9dcabfae049ee584a8748178d96e6 100644 --- a/docs/for-developers/gateway/connector/create-a-connector.md +++ b/docs/for-developers/gateway/connector/create-a-connector.md @@ -117,6 +117,7 @@ The connector has it's own part of configuration, it's mainly parameters that ar | name | default | description | | ----------- | ------- | ------------------------------------------------------------------------------------------------------- | | hasGrouping | false | Define if the connector is able to make query grouping by nominal variable (mainly used for histograms) | +| hasFilters | true | Define if the engine behind the connector is able to manage filters | | hasGalaxy | false | `Deprecated`. Only used by Exareme engine | These elements can be configured by the function `getConfiguration`. diff --git a/docs/for-developers/gateway/graphql/decorators.md b/docs/for-developers/gateway/graphql/decorators.md index 440d4c45285ace4293da52e0e1dbf5e337b8241d..8304f8b393b88462799b2ff774102b849056a44d 100644 --- a/docs/for-developers/gateway/graphql/decorators.md +++ b/docs/for-developers/gateway/graphql/decorators.md @@ -1,6 +1,6 @@ # Decorators -The request and the response made by `GraphQL` are a bit different then what you should expect from a normal REST API. For this purpose and as this is something that is often used, two decorators have been implemented to inject the request with the `@GQLRequest`, the response with `@GQLResponse` or the user with the `@CurrentUser`.  +The request and response made by `GraphQL` are a bit different then what you should expect from a normal REST API. For this purpose and as this is something that is often used, two decorators have been implemented to inject the request. The request can be injected with the decorator `@GQLRequest` and the response with `@GQLResponse` and finally the user can also be injected by using the `@CurrentUser`.  These 3 decorators can only be use in a GraphQL context, it will fail if it's a standard API REST request. diff --git a/docs/for-developers/recipes/README.md b/docs/for-developers/recipes/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5d3d5fd1f1840ca95582ebeabfa31f67b0ae8109 --- /dev/null +++ b/docs/for-developers/recipes/README.md @@ -0,0 +1,2 @@ +# 👩🳠Recipes + diff --git a/docs/for-developers/recipes/add-a-visualization.md b/docs/for-developers/recipes/add-a-visualization.md new file mode 100644 index 0000000000000000000000000000000000000000..ae42ffebffdde906b0ac78290890d7e1e8ebad56 --- /dev/null +++ b/docs/for-developers/recipes/add-a-visualization.md @@ -0,0 +1,3 @@ +# 🚧 Add a visualization + +ResultUnion, gateway and frontend diff --git a/docs/for-developers/recipes/add-an-algorithm-handler-on-exareme.md b/docs/for-developers/recipes/add-an-algorithm-handler-on-exareme.md new file mode 100644 index 0000000000000000000000000000000000000000..925014879ee2d64fb3c024f40d7b79a7064a29ed --- /dev/null +++ b/docs/for-developers/recipes/add-an-algorithm-handler-on-exareme.md @@ -0,0 +1,142 @@ +--- +description: >- + This page describe how algorithm's outputs are processed with Exareme (I & II) + connector +--- + +# Add an algorithm handler on Exareme + +Exareme algorithms' ouputs are processed based on the design pattern [chain of responsibility](https://refactoring.guru/design-patterns/chain-of-responsibility). Basically every algorithm has an handler that can decide to process the output. Each handler has the responsibility to know if it can handle the current output or not.  + +### Add a new handler  + +Each handler should implements the `ResultHandler` interface. The handler can also directly extends the class `BaseHandler` which provides default implementation of the previous interface. + +For this demonstration we will create a new Handler called `MyAlgorithm`. First we will create a new file inside the `src/engine/connectors/exareme/handlers/algorithms` folder. + +{% code title="my-algorithm.handler.ts" lineNumbers="true" %} +```typescript +export default class MyAlgorithmHandler extends BaseHandler { + + handle(experiment: Experiment, data: any, domain?: Domain): void { + ... + } + +} +``` +{% endcode %} + +The handler can either process the request or pass it to the next handler along the chain. For this concern we will define a new method in our algorithm to define the ability or not to handle the request. + +{% code lineNumbers="true" %} +```typescript +export default class MyAlgorithmHandler extends BaseHandler { + public static readonly ALGO_NAME = 'myAlgorithmName'; + + private canHandle(data: any) { + return ( + data && + data.mySuperProperty && + data.algorithmName = MyAlgorithmHandler.ALGO_NAME + ); + } + + handle(experiment: Experiment, data: any, domain? Domain) { + if (!this.canHandle(data: any)) return super.handle(experiment, data, domain); + + //Process the data + } +} +``` +{% endcode %} + +{% hint style="warning" %} +Make sure to call the next handler either by calling directly `this.next(...)` or `super.handler(...)` otherwise it will end the chaining system +{% endhint %} + +The idea of the chaining system is to improve the `Experiment` object that is passed along the chain. This object is acting like a Request object, it's mutable, then you can modify it to fit the need of your handler. + +Here we will add a result inside our experiment for the purpose of the demonstration.  + +{% code lineNumbers="true" %} +```typescript +export default class MyAlgorithmHandler extends BaseHandler { + public static readonly ALGO_NAME = 'myAlgorithmName'; + + private canHandle(data: any) { + return ( + data && + data.mySuperProperty && + data.algorithmName = MyAlgorithmHandler.ALGO_NAME + ); + } + + private getTableResult(data: any): TableResult { + const tableResult: TableResult = { + name: 'Results', + tableStyle: TableStyle.NORMAL, + headers: ['name', 'value'].map((name) => ({ name, type: 'string' })), + data: [ + 'n_obs', + 't_value', + 'ci_upper', + 'cohens_d', + ].map((name) => [ + name, + data[name], + ]), + }; + + return tableResult; + } + + handle(experiment: Experiment, data: any, domain? Domain) { + if (!this.canHandle(data: any)) return super.handle(experiment, data, domain); + + const tableResult = this.getTableResult(data); + if (tableResult) exp.results.push(tableResult); + } +} +``` +{% endcode %} + +In lines 34 and 35 we know that our handler is up to deal with the request, so our handle can produce the result wanted and add it the experiment.  + +Now we can decide to either end the request here or pass it the next handler. As we know that only one algorithm should process the output we can end the request here by not calling the next handle. + +#### Add it to the chaining system + +Now that we have created our algorithm we should add it to the chaining system, open the file `src/engine/connectors/exareme/handlers/index.ts` and simply add our new class to the list + +{% code title="index.ts" lineNumbers="true" %} +```typescript +const start = new PearsonHandler(); + +start + .setNext(new DescriptiveHandler()) + .setNext(new AnovaOneWayHandler()) + .setNext(new PCAHandler()) + .setNext(new LinearRegressionHandler()) + .setNext(new MyAlgorithmHandler()) + .setNext(new RawHandler()); // should be last handler as it works as a fallback (if other handlers could not process the results) + +export default (exp: Experiment, data: unknown, domain: Domain): Experiment => { + start.handle(exp, data, domain); + return exp; +}; + +``` +{% endcode %} + +The handlers' order is important, if you want to check something in priority, just put it in the top of the list.  + +{% hint style="info" %} +This order can be useful if you want to process error at first. You can easily create a connector that could handle global error before passing along the chain system +{% endhint %} + +{% hint style="warning" %} +Don't forget to write a unit test along of your handler, conventionally called `my-algorithm.handler.spec.ts`. +{% endhint %} + + +