From 31a0028f8abb87c74b0e626382cbae57b59d0e36 Mon Sep 17 00:00:00 2001 From: Emric Pichonnier Date: Thu, 2 Mar 2023 17:57:58 +0100 Subject: [PATCH] feat: Data management feature (#82) * feat: add find feature * feat: uodate * fix: Better structure * fix: Better * todos * feat: Operator list * fix: $gt description * Fixing some typos and reformulate some sentences --------- Co-authored-by: Thomas DA ROCHA Co-authored-by: jonas-martinez Co-authored-by: Thomas DA ROCHA <8969556+taorepoara@users.noreply.github.com> --- doc-deps.yml | 2 +- lesta.config.js | 40 +++--- package.json | 4 +- src/markdown/features/data-management.md | 136 ++++++++++++++++++ src/markdown/references/index.md | 4 - src/static/css/.components.css | 3 +- .../css/components/.properties-table.css | 55 ++----- src/static/css/components/.table.css | 32 +++++ src/static/css/main.css | 4 + src/views/references/index.pug | 9 ++ 10 files changed, 221 insertions(+), 68 deletions(-) create mode 100644 src/markdown/features/data-management.md delete mode 100644 src/markdown/references/index.md create mode 100644 src/static/css/components/.table.css create mode 100644 src/views/references/index.pug diff --git a/doc-deps.yml b/doc-deps.yml index 664ecc5..d1986b8 100644 --- a/doc-deps.yml +++ b/doc-deps.yml @@ -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 diff --git a/lesta.config.js b/lesta.config.js index b8e2b92..1860eb6 100644 --- a/lesta.config.js +++ b/lesta.config.js @@ -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', @@ -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 => { @@ -113,7 +113,7 @@ async function pageLister(configuration) { } }); setPagesParent(pages); - sortPages(pages); + pages = sortPages(pages); setPagesChildrenAndNav(pages); return pages; } @@ -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; } diff --git a/package.json b/package.json index d7c01ea..96acdaf 100644 --- a/package.json +++ b/package.json @@ -70,8 +70,8 @@ "from": "^/todo-list-guide.html$", "to": "/guides/todo-list-app.html", "type": "permanent" - } + } ] } } -} \ No newline at end of file +} diff --git a/src/markdown/features/data-management.md b/src/markdown/features/data-management.md new file mode 100644 index 0000000..abafd02 --- /dev/null +++ b/src/markdown/features/data-management.md @@ -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 + + + +#### 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. | diff --git a/src/markdown/references/index.md b/src/markdown/references/index.md deleted file mode 100644 index 79287b4..0000000 --- a/src/markdown/references/index.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -description: The Lenra project references. -icon: book-open ---- \ No newline at end of file diff --git a/src/static/css/.components.css b/src/static/css/.components.css index 54909bf..f93d957 100644 --- a/src/static/css/.components.css +++ b/src/static/css/.components.css @@ -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'; \ No newline at end of file +@import 'components/.tab-filter.css'; diff --git a/src/static/css/components/.properties-table.css b/src/static/css/components/.properties-table.css index c84790d..2bec407 100644 --- a/src/static/css/components/.properties-table.css +++ b/src/static/css/components/.properties-table.css @@ -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; @@ -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: ","; } \ No newline at end of file diff --git a/src/static/css/components/.table.css b/src/static/css/components/.table.css new file mode 100644 index 0000000..bddd38b --- /dev/null +++ b/src/static/css/components/.table.css @@ -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; +} \ No newline at end of file diff --git a/src/static/css/main.css b/src/static/css/main.css index 7d7f8e8..49f93ab 100644 --- a/src/static/css/main.css +++ b/src/static/css/main.css @@ -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 { diff --git a/src/views/references/index.pug b/src/views/references/index.pug new file mode 100644 index 0000000..4a03b49 --- /dev/null +++ b/src/views/references/index.pug @@ -0,0 +1,9 @@ +--- +description: The Lenra project references. +icon: book-open +--- + +extends ../.layout.pug + +append content + include ../.children-pages-list.pug \ No newline at end of file