Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Data management feature #82

Merged
merged 9 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc-deps.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
components:
- name: components-api
url: https://github.com/lenra-io/components-api
version: v1.0.0-beta.79
version: v1.0.0-beta.81
filePrefix: lenra-api-docs
40 changes: 24 additions & 16 deletions lesta.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import fm from 'front-matter';

const languageFileRegex = /^(.+)[.]([a-z]{2})([.](md|html))$/
const attributesMatchingRegex = /#\S+|\.\S+|([a-zA-Z0-9_-]+)(=("(\\"|[^"])*"|'(\\'|[^'])*'|\S*))?/g;
const converter = new Showdown.Converter();
const converter = new Showdown.Converter({tables: true});

const customClassExt = {
type: 'output',
Expand Down Expand Up @@ -95,7 +95,7 @@ async function pageLister(configuration) {
});
const markdownPages = await markdownPageLister(configuration);
const apiPages = await apiPageLister(configuration);
const pages = pugPages.slice();
let pages = pugPages.slice();
addPages(pages, markdownPages);
addPages(pages, apiPages);
pages.forEach(page => {
Expand All @@ -113,7 +113,7 @@ async function pageLister(configuration) {
}
});
setPagesParent(pages);
sortPages(pages);
pages = sortPages(pages);
setPagesChildrenAndNav(pages);
return pages;
}
Expand Down Expand Up @@ -243,31 +243,39 @@ function setPagesChildrenAndNav(pages) {
}

/**
* Set the children pages for each dir page and sort the page list
* Sort the page list
* @param {Page[]} pages
*/
function sortPages(pages) {
// Sort the pages without parent in a resulting array
const ret = sortPageLevel(pages.filter(page => !page.properties.parent));
// for each page in the resulting array, add the sorted sub pages
let i = 0;
while (i < ret.length) {
const page = ret[i];
ret.splice(++i, 0, ...sortPageLevel(pages.filter(p => p.properties.parent == page.href)));
}
return ret;
}

/**
* Sort the page list of a specific level
* @param {Page[]} pages
*/
function sortPageLevel(pages) {
pages.sort((p1, p2) => p1.href.localeCompare(p2.href));
const positionnables = pages.filter(p => "position" in p.properties)
.sort((p1, p2) => {
if (p1.properties.parent == p2.properties.parent)
return p1.properties.position - p2.properties.position
return p1.href.localeCompare(p2.href);
});
.sort((p1, p2) => p1.properties.position - p2.properties.position);
positionnables.forEach(page => {
const children = pages.filter(p => p.properties.parent == page.properties.parent);
const firstChildPos = pages.indexOf(children[0]);
const currentPos = pages.indexOf(page);
let targetPos = firstChildPos + Math.max(
Math.min(page.properties.position, children.length - 1),
let targetPos = Math.max(
Math.min(page.properties.position, pages.length - 1),
0
);
if (currentPos != targetPos) {
pages.splice(currentPos, 1);
if (currentPos < targetPos) {
++targetPos;
}
pages.splice(targetPos, 0, page);
}
});
return pages;
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
"from": "^/todo-list-guide.html$",
"to": "/guides/todo-list-app.html",
"type": "permanent"
}
}
]
}
}
}
}
136 changes: 136 additions & 0 deletions src/markdown/features/data-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
Lenra Data system is based on Mongo.
Using our API, you can access and manage this data and utilize the [View component](/references/components-api/components/view.html) to adapt your application interface.

## API

To manage the data in your application, you can utilize our REST API.
To make a basic API call within Listeners, you can use the "api" object that is passed as the third parameter. This object provides you with the server URL and your authentication token.

### CRUD

Create a document, give the content in the body

```js
- POST `${api.url}/app/colls/${coll}/docs`
```

Read a specific document
```js
- GET `${api.url}/app/colls/${coll}/docs/${id}`
```

Update a document, give the changes in the body
```js
- PUT `${api.url}/app/colls/${coll}/docs/${doc._id}`
```

Delete a document
```js
- DELETE `${api.url}/app/colls/${coll}/docs/${doc._id}`
```

### Advanced Mongo functions


#### find

The [MongoDB find function](https://www.mongodb.com/docs/manual/reference/method/db.collection.find/) can find many documents in a collection filtered by the query filter.

Run find request, give find params in body like:
- query: the query filter
- projection: the projection map more details [here](#apiProjection)

```js
- POST `${api.url}/app/colls/${coll}/docs/find`
```

The projection allows you to filter the keys in the return object, by giving a projection map, all keys set to *true* will be returned, the default values are *false*, example:

We have in the *users* collection

```json
{
"_id": "123456",
"name": "John",
"age": 20
}
```

## View

Lenra also allows the use of Mongo find to customize the view's results according to the requested data.
Additionally, this behavior automatically updates the interface when a data point corresponding to the view query is changed.
### Examples

The next example will call the `filteredUsers` view with the user called `Thomas` as input data:

```json
{
"type": "view",
"name": "filteredUsers",
"find": {
"coll": "users",
"query": {
"name": "Thomas"
}
}
}
```

You can get only the names of the users by using this projection:

```json
{
"type": "view",
"name": "userList",
"find": {
"coll": "users",
"projection": {"name": true}
}
}
```

### Limitations

In order to manage realtime refresh of the view we had to implement the Mongo operators in our [query-parser project](https://github.com/lenra-io/query-parser).
Since it takes time to implement all the operators (and that we also have lot of work on Lenra) we only have implemented a short list of them.
We will implement the rest of them soon, but if you want to help you can look at [the list of operator task](https://github.com/lenra-io/query-parser/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22+operator).

### Managed operators

<!-- Get the groups and description from Mongo doc: https://www.mongodb.com/docs/manual/reference/operator/query/ -->

#### Comparison

| Operator | Description |
|==========|=============|
| [{:target="_blank" rel="noopener"}$eq](https://www.mongodb.com/docs/manual/reference/operator/query/eq/) | Matches values that are equal to a specified value. |
| [{:target="_blank" rel="noopener"}$ne](https://www.mongodb.com/docs/manual/reference/operator/query/ne/) | Matches all values that are not equal to a specified value. |
| [{:target="_blank" rel="noopener"}$gt](https://www.mongodb.com/docs/manual/reference/operator/query/gt/) | Matches all values that are not equal to a specified value. |
|
| [{:target="_blank" rel="noopener"}$gte](https://www.mongodb.com/docs/manual/reference/operator/query/gte/) | Matches values that are greater than or equal to a specified value. |
| [{:target="_blank" rel="noopener"}$lt](https://www.mongodb.com/docs/manual/reference/operator/query/lt/) | Matches values that are less than a specified value. |
| [{:target="_blank" rel="noopener"}$lte](https://www.mongodb.com/docs/manual/reference/operator/query/lte/) | Matches values that are less than or equal to a specified value. |
| [{:target="_blank" rel="noopener"}$in](https://www.mongodb.com/docs/manual/reference/operator/query/in/) | Matches any of the values specified in an array. |
| [{:target="_blank" rel="noopener"}$nin](https://www.mongodb.com/docs/manual/reference/operator/query/nin/) | Matches none of the values specified in an array. |

#### Logical

| Operator | Description |
|==========|=============|
| [{:target="_blank" rel="noopener"}$and](https://www.mongodb.com/docs/manual/reference/operator/query/and/) | Joins query clauses with a logical `AND` returns all documents that match the conditions of both clauses. |
| [{:target="_blank" rel="noopener"}$or](https://www.mongodb.com/docs/manual/reference/operator/query/or/) | Inverts the effect of a query expression and returns documents that do *not* match the query expression. |
| [{:target="_blank" rel="noopener"}$not](https://www.mongodb.com/docs/manual/reference/operator/query/not/) | Joins query clauses with a logical `NOR` returns all documents that fail to match both clauses. |
| [{:target="_blank" rel="noopener"}$nor](https://www.mongodb.com/docs/manual/reference/operator/query/nor/) | Joins query clauses with a logical `OR` returns all documents that match the conditions of either clause. |

#### Element

| Operator | Description |
|==========|=============|
| [{:target="_blank" rel="noopener"}$exists](https://www.mongodb.com/docs/manual/reference/operator/query/exists/) | Matches documents that have the specified field. |

#### Array

| Operator | Description |
|==========|=============|
| [{:target="_blank" rel="noopener"}$all](https://www.mongodb.com/docs/manual/reference/operator/query/all/) | Matches arrays that contain all elements specified in the query. |
4 changes: 0 additions & 4 deletions src/markdown/references/index.md

This file was deleted.

3 changes: 2 additions & 1 deletion src/static/css/.components.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@import 'components/.list.css';
@import 'components/.code.css';
@import 'components/.colored-block.css';
@import 'components/.table.css';
@import 'components/.properties-table.css';
@import 'components/.tab.css';
@import 'components/.tab-filter.css';
@import 'components/.tab-filter.css';
55 changes: 11 additions & 44 deletions src/static/css/components/.properties-table.css
Original file line number Diff line number Diff line change
@@ -1,48 +1,15 @@
main>table {
--text-opacity: var(--greyscale-90-opacity);
text-align: left;
border-spacing: 0;
width: 100%;
}

main>table tr>td {
border-bottom: 0.0625rem solid rgba(var(--text-color-data), var(--greyscale-40-opacity));
}

main>table tr:nth-of-type(2n+1) {
background-color: rgba(var(--text-color-data), var(--greyscale-0-opacity));
}

main>table th,
main>table td {
padding: 0.5rem;
}

main>table th {
color: rgb(var(--background-color-data));
background-color: rgb(var(--text-color-data));
}

main>table th:first-of-type {
border-top-left-radius: 0.25rem;
}

main>table th:last-of-type {
border-top-right-radius: 0.25rem;
}

main>table tr:not(.required)>td:first-of-type::after {
content: " (optional)";
main>table.properties tr:not(.required)>td:first-of-type::after {
content: " (optionnal)";
font-size: 0.75rem;
font-style: italic;
color:rgba(var(--text-color-data), calc(var(--text-opacity) * var(--greyscale-80-opacity)))
}

main>table tr.deprecated {
main>table.properties tr.deprecated {
--text-opacity: 0.4;
}

main>table tr.deprecated>td:first-of-type::before {
main>table.properties tr.deprecated>td:first-of-type::before {
--text-opacity: 1;
content: "depreciated";
display: inline-block;
Expand All @@ -55,30 +22,30 @@ main>table tr.deprecated>td:first-of-type::before {
margin-right: 0.5rem;
}

main>table ul.values {
main>table.properties ul.values {
display: inline-block;
}

main>table ul.values::before {
main>table.properties ul.values::before {
content: "(";
}

main>table ul.values::after {
main>table.properties ul.values::after {
content: ")";
}

main>table ul.values>li {
main>table.properties ul.values>li {
display: inline-block;
}

main>table ul.values>li.default {
main>table.properties ul.values>li.default {
text-decoration: underline;
}

main>table ul.values>li:not(:first-of-type) {
main>table.properties ul.values>li:not(:first-of-type) {
margin-left: 0.25rem;
}

main>table ul.values>li:not(:last-of-type)::after {
main>table.properties ul.values>li:not(:last-of-type)::after {
content: ",";
}
32 changes: 32 additions & 0 deletions src/static/css/components/.table.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
main>table {
--text-opacity: var(--greyscale-90-opacity);
text-align: left;
border-spacing: 0;
width: 100%;
}

main>table tr>td {
border-bottom: 0.0625rem solid rgba(var(--text-color-data), var(--greyscale-40-opacity));
}

main>table tr:nth-of-type(2n) {
background-color: rgba(var(--text-color-data), var(--greyscale-0-opacity));
}

main>table th,
main>table td {
padding: 0.5rem;
}

main>table th {
color: rgb(var(--background-color-data));
background-color: rgb(var(--text-color-data));
}

main>table th:first-of-type {
border-top-left-radius: 0.25rem;
}

main>table th:last-of-type {
border-top-right-radius: 0.25rem;
}
4 changes: 4 additions & 0 deletions src/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ main>:not(h2)+h3::before {
margin: 2rem 0;
}

main>:not(h3)+h4 {
margin-top: 1.5rem;
}


@media (min-width: 35rem) {
h1 {
Expand Down
9 changes: 9 additions & 0 deletions src/views/references/index.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
description: The Lenra project references.
icon: book-open
---

extends ../.layout.pug

append content
include ../.children-pages-list.pug