diff --git a/subjects/good-practices/README.md b/subjects/good-practices/README.md index fb28a7fa..9d3625a6 100644 --- a/subjects/good-practices/README.md +++ b/subjects/good-practices/README.md @@ -85,3 +85,7 @@ It is possible to remove painting by adding a layer: ``` By creating a new layer you can remove painting, but "there is always a tradeoff". If we add to much layers it will increase the **composition** and **update tree**. In conclusion you must promote a new layer only if you now you are going to use it. Performance is the key to a good animation. "Performance is the art of avoiding work". + +### UI/UX + +- [Best Practices](https://www.uxpin.com/studio/blog/guide-design-consistency-best-practices-ui-ux-designers/) diff --git a/subjects/graphql/README.md b/subjects/graphql/README.md index 9a6a0927..fe9ef9ec 100644 --- a/subjects/graphql/README.md +++ b/subjects/graphql/README.md @@ -2,112 +2,98 @@ ### Objectives -The objective of this project is to learn graphql query language by creating profiles. It will be provided,\ -by the platform, a graphql endpoint that is connected to the database. So you can query this endpoint to obtain the information you desire.\ +The objective of this project is to learn the query language [graphQL](https://graphql.org/) by creating your profile page. It will be provided,\ +by the platform, a graphQL endpoint that is connected to the database. So you can query this endpoint to obtain the information you desire.\ **Note** that for security reasons some tables are private and some are public, you will only be provided with certain content. -Your profile must have at least: +Your profile must have at least 3 sections of content at your choice, for example: - Basic user identification - XP amount - level - grades +- audits - skills -- statistics -### Instructions - -> Here is a small introduction and advantages of graphQL, if you want to read more about graphQL you can visit there [site](https://graphql.org/) - -GraphQL is a query language for any API endpoint and runtime. The syntax lets you specify what data you want to receive from that API.\ -You must have in mind that this language is used for API endpoints and not database. Unlike SQL,\ -graphql query does not go to your database directly but to your graphql API endpoint which can connect to a database or any other data source. - -You are already familiar with REST, since REST is a robust methodology of creating APIs and not elastic/scalable.\ -It can be at the same time painful, because it requires individual creation of each API, example: `v1/user/item/{id}`, `v1/post/item/{id}` and so on. +Beside those sections it will have a mandatory section for the generation of statistic graphs. -The main feature of graphql compared to REST is that it lets you ask for specific information. And even better then that is the nesting feature. - ---- +### Instructions -### **profile** +You will have to create a profile UI where you can see your own school information. This information/data is present on the graphQL endpoint, where you will have to query it. -You will have to create a profile system where you can see all the info of a student. The information/data is present\ - on the graphQL endpoint, where you will have to query it. +For the UI it will be up to you to design it. But have in mind the principles of a [good UI](https://public.01-edu.org/subjects/good-practices/).\ +Your UI will have a statistic section where you can generate graphs to see more about your journey and achievements on the school. This graphs must be done using [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG). -The display of the information is up to you to design, but it must include: +Here are some combination that you will be able to use for the graphs: -- **Basic user identification**, for example **githubLogin** -- **XP** amount -- **level** -- **grades** -- **skills** -- **statistics** +- XP earned in a time period (progress over time) +- Levels over time +- XP earned by project +- Audit ratio +- Projects `PASS` and `FAIL` ratio +- Piscine (JS/Go) stats + - `PASS` and `FAIL` ratio + - Attempts for each exercise Any other information you desire to display is welcome and will be noted -Beside this information, you will have to create a search engine which returns a selection of students profiles, based on the students: - -- Name -- XP -- level -- skills - -For instance you can search for a student by their `githubLogin` or filter the students by the amount of `XP` or which `level`/`skill` they have. - --- ### Usage -> Here is the list of tables that you are allowed to query, for more information about the graphql endpoint you are going to use, check out the _docs_ _https://[[DOMAIN]]/public/subjects/grapqhl_: +> To test your queries you can access the GraphQL IDE on _https://[[DOMAIN]]/public/subjects/graphql/_ or create your own [**GraphiQL Docs**](https://github.com/graphql/graphiql). This will give you a bigger picture of the tables, attributes and all the types of queries that you can do. + +Here is the list of tables that you are allowed to query (it will be only provided the columns present on the tables): - **User table**: This table will have information about the user - | id | githubLogin | - | --- | ----------: | - | 1 | person1 | - | 2 | person2 | - | 3 | person3 | + | id | login | + | --- | ------: | + | 1 | person1 | + | 2 | person2 | + | 3 | person3 | - **Transactions table**: This table will give you access to XP and audits ratio - | id | type | amount | userId | attrs | createdAt | - | --- | :--: | -----: | -----: | -----------------------: | -------------------------------: | - | 1 | xp | 234 | 1 | `{"objectId": 3001, ...` | 2019-03-14T12:02:23.168726+00:00 | - | 2 | xp | 1700 | 2 | `{"objectId": 3001, ...` | 2019-03-14T12:02:23.168726+00:00 | - | 3 | xp | 175 | 3 | `{"objectId": 3001, ...` | 2019-03-14T12:02:23.168726+00:00 | + | id | type | amount | objectId | userId | + | --- | :--: | -----: | -------: | -----: | + | 1 | xp | 234 | 42 | 1 | + | 2 | xp | 1700 | 2 | 2 | + | 3 | xp | 175 | 64 | 3 | - **Progress_view table**: - | id | userId | attrs | bestResultId | objectId | - | --- | :----: | -----------------------: | -----------: | -------: | - | 1 | 1 | `{}` | 61 | 3001 | - | 2 | 2 | `{"name": "memory", ...` | NULL | 198 | - | 3 | 3 | `{"name": "memory", ...` | 14319 | 177 | + | id | userId | objectId | grade | + | --- | :----: | -------: | ----: | + | 1 | 1 | 3001 | 1 | + | 2 | 2 | 198 | 0 | + | 3 | 3 | 177 | 1 | - **Results table**: Both progress and result table will give you the student progression - | id | createdAt | updatedAt | grade | progressId | attrs | - | --- | --------------------: | --------------------: | ----: | ---------: | ---------------------------: | - | 1 | 2019-07-06T13:52:5... | 2019-07-06T13:52:5... | 0 | 58 | `{}` | - | 2 | 2019-07-06T13:52:5... | 2019-07-06T13:52:5... | 0 | 58 | `{"errors": {"steps": ...}}` | - | 3 | 2019-07-06T13:52:5... | 2019-07-06T13:52:5... | 1 | 58 | `{}` | + | id | objectId | userId | grade | progressId | type | + | --- | -------: | -----: | ----: | ---------: | ---: | + | 1 | 3 | 1 | 0 | 58 | | + | 2 | 23 | 1 | 0 | 58 | | + | 3 | 41 | 6 | 1 | 58 | | - **Object table**: This table will give you information about all objects (exercises/projects) - | id | name | type | status | attrs | childrenAttrs | createdAt | updatedAt | - | --- | ---: | -------: | -----: | ------------------------: | ------------: | --------------------: | --------------------: | - | 1 | 0 | exercise | draft | `{"language": "dom", ...` | `{}` | 2019-03-14T12:02:2... | 2019-03-14T12:02:2... | - | 2 | 0 | project | online | `{"language": "go", ...` | `{}` | 2019-03-14T12:02:2... | 2019-03-14T12:02:2... | - | 3 | 1 | exercise | online | `{"language": "js", ...` | `{}` | 2019-03-14T12:02:2... | 2019-03-14T12:02:2... | + | id | name | type | attrs | childrenAttrs | + | --- | ---: | -------: | ------------------------: | ------------: | + | 1 | 0 | exercise | `{"language": "dom", ...` | `{}` | + | 2 | 0 | project | `{"language": "go", ...` | `{}` | + | 3 | 1 | exercise | `{"language": "js", ...` | `{}` | + +Examples: Lets take for instance the table `user` and try to query it: @@ -121,7 +107,7 @@ Lets take for instance the table `user` and try to query it: } ``` -This simple query will return an array with the `ids` of the users. Imagine if you wanted the `githubLogin`,\ +This simple query will return an array with the `id`s of the users. Imagine if you wanted the `login`,\ you could just add this attribute to the query, example: ```js @@ -129,7 +115,7 @@ you could just add this attribute to the query, example: query { user { id - githubLogin + login } } } @@ -137,31 +123,31 @@ you could just add this attribute to the query, example: You can try to `curl` the API endpoint to see the result given by the server: -- `curl "https://[[DOMANIN]]/api/graphql-engine/v1/graphql" --data '{"query":"{user{id githubLogin}}"}'` +- `curl "https://[[DOMANIN]]/api/graphql-engine/v1/graphql" --data '{"query":"{user{id login}}"}'` Here is another example of a query using the table `user`: ```js { - query: { + query { user(where: { id: { _eq: 6 }}) { id - githubLogin + login } } } ``` **Note** that for this query is required the introduction of variables (arguments)\ - so it will return just one user, the user that as the id equal to `6`. + so it will return just one user, the user that as the `id` equal to `6`. You can see the result using `curl`: -- `curl "https://[[DOMANIN]]/api/graphql-engine/v1/graphql" --data '{"query":"{user(where:{id:{_eq:6}}){id githubLogin}}"}'` +- `curl "https://[[DOMANIN]]/api/graphql-engine/v1/graphql" --data '{"query":"{user(where:{id:{_eq:6}}){id login}}"}'` -In graphql the usage of arguments can be specified in the schema of the API endpoint. Here is the _docs_ for the graphql endpoint you are going to use, _https://[[DOMAIN]]/public/subjects/grapqhl_ +In graphQL the usage of arguments can be specified in the schema of the API. Like said above you can visit the _docs_ for the graphQL endpoint you are going to use, _https://[[DOMAIN]]/public/subjects/grapqhl_ -nesting fetching, using the : +Example using the nesting, using the result and user table : ```js { @@ -169,17 +155,18 @@ nesting fetching, using the : id user { id - githubLogin + login } } } ``` -For this example we ask for the results `id` and `user`s that are associated to the `result`, requesting the users `name`s and `id`s.\ +For this example we ask for the results `id` and `user`s that are associated to the `result`, requesting the users `name`s and `id`s. This project will help you learn about: -- [Graphql](https://graphql.org/) language -- Custom search operations (`include`/`exclude`/`fuzzy`) +- [GraphQL](https://graphql.org/) +- [GraphiQL](https://github.com/graphql/graphiql) - Basics of human-computer interface + - UI/UX diff --git a/subjects/graphql/index.html b/subjects/graphql/index.html index 51cc370e..6467fc74 100644 --- a/subjects/graphql/index.html +++ b/subjects/graphql/index.html @@ -1,119 +1,37 @@ - - - Graphql Doc - - - - - - -
-

Schema Documentation

-
- -

A Graphql schema provides a root type for each kind of operation

-
-

ROOT TYPES

-
-
-
-
- - + + Simple GraphiQL Example + + + +
+ + + + + + + + \ No newline at end of file diff --git a/subjects/graphql/lib/schema.js b/subjects/graphql/lib/schema.js deleted file mode 100644 index 5eec38a8..00000000 --- a/subjects/graphql/lib/schema.js +++ /dev/null @@ -1,163 +0,0 @@ -const backImg = - 'https://cdn1.iconfinder.com/data/icons/thin-ui-1/100/Noun_Project_100Icon_1px_grid_thin_ic_arrow_left_simple-512.png' -const body = document.body -const docDisplay = document.querySelector('.display-doc') -const exist = () => document.querySelector('.back') -const removeComments = (obj) => - Object.fromEntries(obj.filter((v) => v[0] !== 'comment')) - -const getData = async (pathToFile) => { - const data = await fetch(pathToFile) - .then((data) => data.json()) - .catch(console.log) - return data -} - -const generateLinks = (k, v) => { - const h4 = document.createElement('h4') - const a = document.createElement('a') - a.innerText = v - h4.innerHTML = k - h4.appendChild(a) - docDisplay.appendChild(h4) - return a -} - -const generateAllQueries = (data) => { - const docTitle = document.querySelector('.doc-title') - docDisplay.innerHTML = '' - const back = backArrow() - docTitle.appendChild(back) - for (let obj of data.types) { - for (const [k, _] of Object.entries(removeComments(Object.entries(obj)))) { - generateContent(k, obj) - } - } -} - -const loadRootTypes = async () => { - const data = await getData('./lib/schema.json') - for (let v of data.root_types) { - const h4 = document.createElement('h4') - const a = document.createElement('a') - a.addEventListener('click', (event) => changeContent(event, data)) - - for (const [k, value] of Object.entries(v)) { - a.innerText = value - h4.innerHTML = `${k}: ` - h4.appendChild(a) - docDisplay.appendChild(h4) - } - } - const a = generateLinks('all: ', 'all_available_queries') - a.addEventListener('click', () => generateAllQueries(data)) -} - -const generateContent = (t, data) => { - docDisplay.innerHTML += `type ${t.toUpperCase()} {` - for (const [k, v] of Object.entries(data[t])) { - generateLinks(` ${k}: `, v) - } - docDisplay.innerHTML += `}

` - if (t === 'query') { - for (let v of document.getElementsByTagName('a')) { - v.addEventListener('click', (e) => changeContent(e, data)) - } - } -} - -const backArrow = () => { - const title = document.querySelector('.title') - const typeDescription = document.querySelector('.comment') - const contType = document.querySelector('.doc-type') - const origType = contType.innerText - const origTitle = title.innerText - const origTypeDescription = typeDescription.innerText - const back = document.createElement('img') - back.className = 'back' - back.src = backImg - - back.addEventListener('click', () => { - back.remove() - docDisplay.innerHTML = '' - title.innerText = origTitle - contType.innerText = origType - typeDescription.innerText = origTypeDescription - loadRootTypes() - }) - return back -} - -const allArgs = (data) => { - for (const [k, v] of Object.entries(data.arguments)) { - docDisplay.innerHTML += `

${k}: (${v.description}) // ${v.comment}

Expressions:
` - for (const exp of v.expressions) { - docDisplay.innerHTML += `

${exp}

` - } - docDisplay.innerHTML += `Example:

${v.example}



` - } -} - -const changeContent = ({ target }, data) => { - const title = document.querySelector('.title') - const typeDescription = document.querySelector('.comment') - const contType = document.querySelector('.doc-type') - const docTitle = document.querySelector('.doc-title') - - const t = target.innerText - const back = backArrow() - - title.innerText = t.toUpperCase() - contType.innerText = `${t.toUpperCase()} fields` - docDisplay.innerHTML = '' - if (/\[\w*\!\]\!/g.test(t)) { - const b = t.replace(/\[|\]|\!/g, '') - const obj = data.types.filter((v) => v[b])[0] - typeDescription.innerText = obj.comment - generateContent(b, obj) - } else if (t === 'arguments') { - allArgs(data) - !exist() && docTitle.appendChild(back) - } else { - generateContent(t, data) - !exist() && docTitle.appendChild(back) - } -} - -loadRootTypes() - -/* search */ -const updateResult = (dataToSearch, { target }) => { - docDisplay.innerHTML = '' - - dataToSearch.search.map((type) => - target.value.split(' ').map((w) => { - if (type.toLowerCase().indexOf(w.toLowerCase()) !== -1) { - docDisplay.innerHTML += `
  • ${type}
  • ` - document - .querySelectorAll('.query-result') - .forEach((ele) => - ele.addEventListener('click', (e) => changeContent(e, dataToSearch)) - ) - } - }) - ) -} - -const initSearch = async () => { - const data = await getData('./lib/schema.json') - const input = document.querySelector('.search') - - input.addEventListener('focus', () => { - const bg = document.querySelector('.back') - if (!bg) { - const back = backArrow() - document.querySelector('.doc-title').appendChild(back) - } - docDisplay.innerHTML = '' - }) - input.oninput = (e) => updateResult(data, e) -} - -initSearch() -/*--------------*/ diff --git a/subjects/graphql/lib/schema.json b/subjects/graphql/lib/schema.json deleted file mode 100644 index 5c7e2bd7..00000000 --- a/subjects/graphql/lib/schema.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "search": [ - "[user!]!", - "[object!]!", - "[transaction!]!", - "[progress_view!]!", - "[result!]!", - "query", - "arguments" - ], - "root_types": [{ "query": "query" }, { "arguments": "arguments" }], - "query": { - "user": "[user!]!", - "object": "[object!]!", - "transaction": "[transaction!]!", - "progress_view": "[progress_view!]!", - "result": "[result!]!" - }, - "types": [ - { - "user": { - "id": "ID!", - "attrs": "Jsonb!", - "createdAt": "String!", - "discordDMChannelId": "String!", - "discordId": "String!", - "discordLogin": "String!", - "githubId": "String!", - "githubLogin": "String!", - "profile": "Jsonb!", - "updatedAt": "String!" - }, - "comment": "Fetch data from the table: \"user\"\nThis table will have information about the user" - }, - { - "object": { - "id": "ID!", - "attrs": "Jsonb!", - "authorId": "String!", - "childrenAttrs": "String!", - "createdAt": "String!", - "externalRelationUrl": "String!", - "name": "String!", - "type": "String!", - "status": "String!", - "updatedAt": "String!" - }, - "comment": "Fetch data from the table: \"object\"\nThis table will give you information about all objects (exercises/projects)" - }, - { - "transaction": { - "id": "ID!", - "attrs": "Jsonb!", - "amount": "Int!", - "createdAt": "String!", - "type": "String!", - "userId": "Int!" - }, - "comment": "Fetch data from the table: \"transaction\"\nThis table will give you access to XP and audits ratio" - }, - { - "progress_view": { - "id": "ID!", - "attrs": "Jsonb!", - "bestResultId": "Int!", - "createdAt": "String!", - "eventId": "Int!", - "groupId": "Int!", - "objectId": "Int!", - "updatedAt": "String!", - "userId": "Int!" - }, - "comment": "Fetch data from the table: \"progress\"\nBoth progress and result table will give you the student progression" - }, - { - "result": { - "id": "ID!", - "progressId": "Int!", - "attrs": "Jsonb!", - "createdAt": "String!", - "grade": "Int!", - "updatedAt": "String!" - }, - "comment": "Fetch data from the table: \"result\"\nBoth progress and result table will give you the student progression" - } - ], - "arguments": { - "where": { - "description": "bool_exp", - "expressions": [ - "_eq (equal)", - "_gt (grater then)", - "_gte (grater then equal)", - "_in (in)", - "_is_null (boolean)", - "_lt (lower then)", - "_lte (lower then equal)", - "_neq (not equal)", - "_nin (not in)" - ], - "example": "user(where: {id: { _eq: x } }){\n id \n}", - "comment": "filter the rows returned" - }, - "order_by": { - "description": "[order_by!]", - "expressions": [ - "asc (ascending)", - "asc_nulls_first", - "asc_nulls_last", - "desc (descending)", - "desc_nulls_first", - "asc_nulls_last" - ], - "example": "user(order_by: {id: desc }){\n id \n}", - "comment": "sort the rows by one or more columns" - }, - "limit": { - "description": "Int", - "expressions": ["Int"], - "example": "user(limit: 1 ){\n id \n}", - "comment": "limit the number of rows returned" - }, - "distinct_on": { - "description": "column name", - "expressions": ["column name"], - "example": "object(distinct_on: name, where: { name:{ _eq:\"forum\" } }){\n name \n}", - "comment": "distinct select on columns" - }, - "offset": { - "description": "int", - "expressions": ["Int"], - "example": "object(distinct_on: name, where: { name:{ _eq:\"forum\" } }){\n name\n }", - "comment": "skip the first n rows by one or more columns" - } - } -}