lesli_audit 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/lesli_audit/application.js +2083 -1626
  3. data/app/controllers/lesli_audit/dashboard/components_controller.rb +60 -0
  4. data/app/controllers/lesli_audit/dashboards_controller.rb +26 -49
  5. data/app/controllers/lesli_audit/requests_controller.rb +36 -50
  6. data/app/controllers/lesli_audit/users_controller.rb +5 -53
  7. data/app/helpers/lesli_audit/dashboard/components_helper.rb +4 -0
  8. data/app/models/lesli_audit/account/request.rb +4 -0
  9. data/app/models/lesli_audit/account.rb +8 -0
  10. data/app/models/lesli_audit/dashboard/component.rb +18 -0
  11. data/app/models/lesli_audit/dashboard.rb +30 -2
  12. data/app/services/lesli_audit/{request_services.rb → request_service.rb} +14 -3
  13. data/app/views/lesli_audit/dashboard/components/_component.html.erb +2 -0
  14. data/app/views/lesli_audit/dashboard/components/_form.html.erb +17 -0
  15. data/app/views/lesli_audit/dashboard/components/edit.html.erb +1 -0
  16. data/app/views/lesli_audit/dashboard/components/index.html.erb +14 -0
  17. data/app/views/lesli_audit/dashboard/components/new.html.erb +9 -0
  18. data/app/views/lesli_audit/dashboard/components/show.html.erb +1 -0
  19. data/app/views/lesli_audit/dashboards/edit.html.erb +1 -10
  20. data/app/views/lesli_audit/partials/_engine-navigation.html.erb +2 -2
  21. data/app/views/lesli_audit/requests/index.html.erb +1 -14
  22. data/app/views/lesli_audit/users/index.html.erb +1 -14
  23. data/config/locales/translations.en.yml +17 -4
  24. data/config/locales/translations.es.yml +17 -4
  25. data/config/routes.rb +17 -3
  26. data/db/seeds.rb +4 -1
  27. data/lib/lesli_audit/version.rb +1 -1
  28. data/lib/vue/application.js +50 -6
  29. data/lib/vue/apps/dashboards/components/roles.vue +71 -0
  30. data/lib/vue/apps/dashboards/components/users.vue +71 -0
  31. data/lib/vue/apps/dashboards/show.vue +8 -0
  32. data/lib/vue/apps/requests/index.vue +43 -41
  33. data/lib/vue/apps/users/index.vue +31 -0
  34. data/lib/vue/components/requests.vue +2 -0
  35. data/lib/vue/components/visitors.vue +3 -3
  36. data/lib/vue/stores/analytics.js +4 -1
  37. data/lib/vue/stores/request.js +4 -4
  38. data/lib/vue/stores/translations.json +32 -22
  39. data/readme.md +9 -9
  40. metadata +23 -10
  41. data/app/assets/javascripts/lesli_audit/application.js.LICENSE.txt +0 -327
  42. /data/db/migrate/v1.0/{0803000110_create_lesli_audit_accounts.rb → 0503000110_create_lesli_audit_accounts.rb} +0 -0
  43. /data/db/migrate/v1.0/{0803050110_create_lesli_audit_dashboards.rb → 0503050110_create_lesli_audit_dashboards.rb} +0 -0
  44. /data/db/migrate/v1.0/{0803050210_create_lesli_audit_dashboard_components.rb → 0503050210_create_lesli_audit_dashboard_components.rb} +0 -0
  45. /data/db/migrate/v1.0/{0803100010_create_lesli_audit_account_requests.rb → 0503100010_create_lesli_audit_account_requests.rb} +0 -0
  46. /data/db/migrate/v1.0/{0803110010_create_lesli_audit_user_requests.rb → 0503110010_create_lesli_audit_user_requests.rb} +0 -0
@@ -30,10 +30,23 @@ Building a better future, one line of code at a time.
30
30
  */
31
31
 
32
32
 
33
- // ·
33
+ // · Import Lesli builders
34
34
  import application from "Lesli/application"
35
+ import translation from "Lesli/translation"
36
+
37
+
38
+ // · Import engine translations
39
+ import translations from "LesliAudit/stores/translations.json"
40
+
35
41
 
42
+ // ·
36
43
  import appAnalytics from "LesliAudit/apps/analytics/index.vue"
44
+ import appRequests from "LesliAudit/apps/requests/index.vue"
45
+ import appUsers from "LesliAudit/apps/users/index.vue"
46
+
47
+ //import appDashboardShow from "LesliAudit/apps/dashboards/show.vue"
48
+ import appDashboardShow from "Lesli/shared/dashboards/apps/show.vue"
49
+ import appDashboardEdit from "Lesli/shared/dashboards/apps/edit.vue"
37
50
 
38
51
  // ·
39
52
  /*
@@ -51,16 +64,50 @@ import appAccountsActivities from "CloudAudit/apps/accounts/activities.vue"
51
64
 
52
65
  import appSecuritySessions from "CloudAudit/apps/security/sessions.vue"
53
66
  import appSecurityPasswords from "CloudAudit/apps/security/passwords.vue"
54
-
55
- import appRequests from "CloudAudit/apps/requests/index.vue"
56
67
  */
57
68
 
58
69
 
59
70
  // ·
71
+ import componentDashboardUsers from "LesliAudit/apps/dashboards/components/users.vue"
72
+ import componentDashboardRoles from "LesliAudit/apps/dashboards/components/roles.vue"
73
+
74
+
75
+ // ·
76
+ const dashboardProps = {
77
+ components: {
78
+ "audit-users": componentDashboardUsers,
79
+ "audit-roles": componentDashboardRoles
80
+ }
81
+ }
82
+
83
+
84
+ // · Buil Lesli translations
85
+ translation(translations)
86
+
87
+
88
+ // · Build a new Lesli application
60
89
  application("LesliAudit", [{
90
+ path: "/",
91
+ component: appDashboardShow,
92
+ props: dashboardProps
93
+ }, {
94
+ path: "/dashboard",
95
+ component: appDashboardShow,
96
+ props: dashboardProps
97
+ }, {
98
+ path: "/dashboards/:id/edit",
99
+ component: appDashboardEdit,
100
+ props: dashboardProps
101
+ }, {
61
102
  path: "/analytics",
62
103
  component: appAnalytics,
63
104
  props: { engine: "audit" }
105
+ }, {
106
+ path: "/requests",
107
+ component: appRequests
108
+ }, {
109
+ path: "/users",
110
+ component: appUsers,
64
111
  }
65
112
  /*{
66
113
  path: "/",
@@ -90,9 +137,6 @@ application("LesliAudit", [{
90
137
  }, {
91
138
  path: "/analytics/trends",
92
139
  component: appAnalyticsTrends
93
- }, {
94
- path: "/requests",
95
- component: appRequests
96
140
  }, {
97
141
  path: "/security/sessions",
98
142
  component: appSecuritySessions
@@ -0,0 +1,71 @@
1
+ <script setup>
2
+ /*
3
+ Lesli
4
+
5
+ Copyright (c) 2023, Lesli Technologies, S. A.
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see http://www.gnu.org/licenses/.
19
+
20
+ Lesli · Ruby on Rails SaaS Development Framework.
21
+
22
+ Made with ♥ by https://www.lesli.tech
23
+ Building a better future, one line of code at a time.
24
+
25
+ @contact hello@lesli.tech
26
+ @website https://www.lesli.tech
27
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
+
29
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // ·
31
+ */
32
+
33
+
34
+ // ·
35
+ import { onMounted } from "vue"
36
+
37
+
38
+ // ·
39
+ import { useUsers } from "Lesli/stores/users"
40
+
41
+
42
+ // ·
43
+ const storeUsers = useUsers()
44
+
45
+
46
+ // ·
47
+ const props = defineProps({
48
+ component: {
49
+ type: Object,
50
+ required: true
51
+ }
52
+ })
53
+
54
+
55
+ // ·
56
+ onMounted(() => {
57
+ storeUsers.getUsersList()
58
+ })
59
+
60
+ </script>
61
+ <template>
62
+ <lesli-card>
63
+ <h6 class="title is-6 mb-4">{{ props.component.name }}</h6>
64
+ <p>{{ storeUsers.list.length }}</p>
65
+ </lesli-card>
66
+ </template>
67
+ <style scoped>
68
+ p {
69
+ font-size: 2rem;
70
+ }
71
+ </style>
@@ -0,0 +1,71 @@
1
+ <script setup>
2
+ /*
3
+ Lesli
4
+
5
+ Copyright (c) 2023, Lesli Technologies, S. A.
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see http://www.gnu.org/licenses/.
19
+
20
+ Lesli · Ruby on Rails SaaS Development Framework.
21
+
22
+ Made with ♥ by https://www.lesli.tech
23
+ Building a better future, one line of code at a time.
24
+
25
+ @contact hello@lesli.tech
26
+ @website https://www.lesli.tech
27
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
+
29
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // ·
31
+ */
32
+
33
+
34
+ // ·
35
+ import { onMounted } from "vue"
36
+
37
+
38
+ // ·
39
+ import { useUsers } from "Lesli/stores/users"
40
+
41
+
42
+ // ·
43
+ const storeUsers = useUsers()
44
+
45
+
46
+ // ·
47
+ const props = defineProps({
48
+ component: {
49
+ type: Object,
50
+ required: true
51
+ }
52
+ })
53
+
54
+
55
+ // ·
56
+ onMounted(() => {
57
+ storeUsers.getUsersList()
58
+ })
59
+
60
+ </script>
61
+ <template>
62
+ <lesli-card>
63
+ <h6 class="title is-6 mb-4">{{ props.component.name }}</h6>
64
+ <p>{{ storeUsers.list.length }}</p>
65
+ </lesli-card>
66
+ </template>
67
+ <style scoped>
68
+ p {
69
+ font-size: 2rem;
70
+ }
71
+ </style>
@@ -0,0 +1,8 @@
1
+ <script setup>
2
+
3
+ import LesliDashboard from "Lesli/shared/dashboards/apps/show.vue"
4
+
5
+ </script>
6
+ <template>
7
+ <lesli-dashboard></lesli-dashboard>
8
+ </template>
@@ -1,18 +1,33 @@
1
1
  <script setup>
2
2
  /*
3
- Copyright (c) 2022, all rights reserved.
4
3
 
5
- All the information provided by this platform is protected by international laws related to
6
- industrial property, intellectual property, copyright and relative international laws.
7
- All intellectual or industrial property rights of the code, texts, trade mark, design,
8
- pictures and any other information belongs to the owner of this platform.
4
+ Lesli
9
5
 
10
- Without the written permission of the owner, any replication, modification,
11
- transmission, publication is strictly forbidden.
6
+ Copyright (c) 2023, Lesli Technologies, S. A.
12
7
 
13
- For more information read the license file including with this software.
8
+ This program is free software: you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation, either version 3 of the License, or
11
+ (at your option) any later version.
14
12
 
15
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
13
+ This program is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with this program. If not, see http://www.gnu.org/licenses/.
20
+
21
+ Lesli · Ruby on Rails SaaS Development Framework.
22
+
23
+ Made with ♥ by https://www.lesli.tech
24
+ Building a better future, one line of code at a time.
25
+
26
+ @contact hello@lesli.tech
27
+ @website https://www.lesli.tech
28
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
29
+
30
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
16
31
  // ·
17
32
  */
18
33
 
@@ -22,28 +37,18 @@ import { ref, reactive, onMounted, watch, computed } from "vue"
22
37
 
23
38
 
24
39
  // · import lesli stores
25
- import { useLogRequest } from "CloudAudit/stores/request"
40
+ import { useRequests } from "LesliAudit/stores/request"
26
41
 
27
42
 
28
43
  // · implement stores
29
- const store = useLogRequest()
44
+ const storeRequests = useRequests()
30
45
 
31
46
 
32
47
  // · define variables
33
48
  const columns = [{
34
49
  field: "id",
35
50
  label: "ID"
36
- }, {
37
- field: "email",
38
- label: "Email",
39
- sort: true
40
- }, {
41
- field: "request_agent",
42
- label: "Device"
43
- }, {
44
- field: "request_method",
45
- label: "Method"
46
- }, {
51
+ }, {
47
52
  field: "request_controller",
48
53
  label: "Controller",
49
54
  sort: true
@@ -51,23 +56,20 @@ const columns = [{
51
56
  field: "request_action",
52
57
  label: "Action"
53
58
  }, {
54
- field: "created_at_date",
59
+ field: "request_count",
60
+ align: "center",
61
+ label: "Count"
62
+ }, {
63
+ field: "created_at",
55
64
  label: "Date"
56
65
  }]
57
66
 
58
67
 
59
68
  // · initializing
60
69
  onMounted(() => {
61
- store.fetchLogsIfEmpty()
70
+ storeRequests.fetch()
62
71
  })
63
72
 
64
-
65
- function itemProjection(item){ console.log("itemprojection", item) }
66
- function selectItemEventHandler(item){ console.log("selectItem", item) }
67
- function onInputEventHandler(item){ console.log("onInput", item) }
68
- function onFocusEventHandler(item){ console.log("onFocus", item) }
69
- function onBlurEventHandler(item){ console.log("onBlur", item) }
70
-
71
73
  </script>
72
74
  <script>
73
75
  export default {
@@ -79,12 +81,12 @@ export default {
79
81
  }
80
82
  </script>
81
83
  <template>
82
- <section class="application-component">
84
+ <lesli-application-container>
83
85
  <lesli-header
84
- title="Users activity"
85
- @reload="store.fetchLogs()">
86
+ title="Account requests"
87
+ @reload="storeRequests.fetchLogs()">
86
88
  </lesli-header>
87
- <lesli-toolbar @search="store.search">
89
+ <lesli-toolbar @search="storeRequests.search">
88
90
  <!--
89
91
  <Autocomplete
90
92
  id="typeahead_id"
@@ -111,13 +113,13 @@ export default {
111
113
  -->
112
114
  </lesli-toolbar>
113
115
  <lesli-table
114
- @sort="store.sort"
115
- @paginate="store.paginate"
116
- :pagination="store.pagination"
117
- :loading="store.loading"
116
+ @sort="storeRequests.sort"
117
+ @paginate="storeRequests.paginate"
118
+ :pagination="storeRequests.pagination"
119
+ :loading="storeRequests.loading"
118
120
  :columns="columns"
119
- :records="store.records"
121
+ :records="storeRequests.records"
120
122
  @click="showUser">
121
123
  </lesli-table>
122
- </section>
124
+ </lesli-application-container>
123
125
  </template>
@@ -0,0 +1,31 @@
1
+ <script setup>
2
+
3
+ </script>
4
+ <template>
5
+ <lesli-application-container>
6
+ <lesli-columns>
7
+ <lesli-column>
8
+ <lesli-card title="Users registered">
9
+ <p class="number">160</p>
10
+ </lesli-card>
11
+ </lesli-column>
12
+ <lesli-column>
13
+ <lesli-card title="Active roles">
14
+ <p class="number">12</p>
15
+ </lesli-card>
16
+ </lesli-column>
17
+ <lesli-column>
18
+ <lesli-card title="Active descriptors">
19
+ <p class="number">70</p>
20
+ </lesli-card>
21
+ </lesli-column>
22
+ </lesli-columns>
23
+ </lesli-application-container>
24
+ </template>
25
+ <style>
26
+ .number {
27
+ padding: 1rem;
28
+ font-size: 3rem;
29
+ text-align: center;
30
+ }
31
+ </style>
@@ -46,12 +46,14 @@ const storeAnalytics = useAnalytics()
46
46
  <template>
47
47
  <div class="columns">
48
48
  <div class="column">
49
+ <h3>Most active users</h3>
49
50
  <lesli-table
50
51
  :columns="storeAnalytics.users.columns"
51
52
  :records="storeAnalytics.users.records">
52
53
  </lesli-table>
53
54
  </div>
54
55
  <div class="column">
56
+ <h3>Most active controllers</h3>
55
57
  <lesli-table
56
58
  :columns="storeAnalytics.controllers.columns"
57
59
  :records="storeAnalytics.controllers.records">
@@ -36,7 +36,7 @@ import { ref, reactive, onMounted, watch, computed } from "vue"
36
36
 
37
37
 
38
38
  // · import Lesli components
39
- import { lesliChartLine } from "lesli-vue/components"
39
+ import { ChartLine } from "lesli-vue/components"
40
40
 
41
41
 
42
42
  // · import stores
@@ -67,10 +67,10 @@ watch(() => storeAnalytics.visitors.records, () => {
67
67
  </script>
68
68
  <template>
69
69
  <lesli-application-component>
70
- <lesli-chart-line
70
+ <chart-line
71
71
  :title="'Visitors'"
72
72
  :series="series"
73
73
  :labels="labels">
74
- </lesli-chart-line>
74
+ </chart-line>
75
75
  </lesli-application-component>
76
76
  </template>
@@ -68,7 +68,10 @@ export const useAnalytics = defineStore("analytics", {
68
68
  fetchVisits() {
69
69
  this.visitors.loading = true
70
70
  this.http.get(this.url.audit("analytics/visitors")).then(result => {
71
- this.visitors.records = result.reverse()
71
+ this.visitors.records = result.map(record => {
72
+ record.date = this.date(record.date).date()
73
+ return record
74
+ }).reverse()
72
75
  }).finally(() => {
73
76
  this.visitors.loading = false
74
77
  })
@@ -21,7 +21,7 @@ import { defineStore } from "pinia"
21
21
 
22
22
 
23
23
  // ·
24
- export const useLogRequest = defineStore("logRequest", {
24
+ export const useRequests = defineStore("Requests", {
25
25
  state: () => {
26
26
  return {
27
27
  date: "",
@@ -45,13 +45,13 @@ export const useLogRequest = defineStore("logRequest", {
45
45
  this.fetchLogs(this.url.audit("requests").paginate(page), false)
46
46
  },
47
47
 
48
- fetchLogsIfEmpty() {
48
+ fetch() {
49
49
  if (this.records.length <= 0) {
50
- this.fetchLogs()
50
+ this.getRequests()
51
51
  }
52
52
  },
53
53
 
54
- fetchLogs(url=this.url.audit("requests"), loading=true) {
54
+ getRequests(url=this.url.audit("requests"), loading=true) {
55
55
 
56
56
  this.loading = loading
57
57
 
@@ -1,37 +1,47 @@
1
1
  {
2
2
  "en": {
3
3
  "lesli": {
4
- "shared": {
5
- "title_lesli": ":lesli.shared.title_lesli:"
4
+ "application": {
5
+ "navigation_logout": "Logout",
6
+ "navigation_my_profile": "My profile"
6
7
  },
7
- "users": {
8
- "title_users": "Users"
9
- }
10
- },
11
- "lesli_audit": {
12
8
  "shared": {
13
- "title_lesli": ":lesli.shared.title_lesli:"
14
- },
15
- "users": {
16
- "title_users": "Users"
9
+ "button_add_new": "Add new",
10
+ "button_delete": "Delete",
11
+ "button_edit": "Edit",
12
+ "button_list": "List",
13
+ "button_reload": "Reload",
14
+ "button_save": "Save",
15
+ "button_settings": "Settings",
16
+ "button_show": "Show",
17
+ "view_discussions": "Discussions",
18
+ "view_files": "Files",
19
+ "view_quick_actions": "Quick actions",
20
+ "view_status_active": "Active",
21
+ "view_status_inactive": "Inactive"
17
22
  }
18
23
  }
19
24
  },
20
25
  "es": {
21
26
  "lesli": {
22
- "shared": {
23
- "title_lesli": "Lesli en español "
27
+ "application": {
28
+ "navigation_logout": "Cerrar sesión",
29
+ "navigation_my_profile": "Mi perfil"
24
30
  },
25
- "users": {
26
- "title_users": "Usuarios"
27
- }
28
- },
29
- "lesli_audit": {
30
31
  "shared": {
31
- "title_lesli": "Lesli en español "
32
- },
33
- "users": {
34
- "title_users": "Usuarios"
32
+ "button_add_new": "Agregar nuevo",
33
+ "button_delete": "Eliminar",
34
+ "button_edit": "Editar",
35
+ "button_list": "Lista",
36
+ "button_reload": "Recargar",
37
+ "button_save": "Guardar",
38
+ "button_settings": "Configuración",
39
+ "button_show": "Ver",
40
+ "view_discussions": "Discusiones",
41
+ "view_files": "Archivos",
42
+ "view_quick_actions": "Acciones rapidas",
43
+ "view_status_active": "Activo",
44
+ "view_status_inactive": "Inactivo"
35
45
  }
36
46
  }
37
47
  }
data/readme.md CHANGED
@@ -1,12 +1,12 @@
1
1
  <p align="center">
2
- <img width="90" alt="LesliCloud logo" src="./app/assets/images/lesli_admin/admin-logo.svg" />
2
+ <img width="90" alt="LesliCloud logo" src="./app/assets/images/lesli_audit/audit-logo.svg" />
3
3
  <h3 align="center">Administration area for the Lesli Framework.</h3>
4
4
  </p>
5
5
 
6
6
  <hr/>
7
7
  <p align="center">
8
- <a target="blank" href="https://rubygems.org/gems/lesli_admin">
9
- <img src="https://badge.fury.io/rb/lesli_admin.svg" alt="Gem Version" height="18">
8
+ <a target="blank" href="https://rubygems.org/gems/lesli_audit">
9
+ <img src="https://badge.fury.io/rb/lesli_audit.svg" alt="Gem Version" height="22">
10
10
  </a>
11
11
  </p>
12
12
  <hr/>
@@ -14,8 +14,8 @@
14
14
  ### Quick start
15
15
 
16
16
  ```shell
17
- # Add LesliAdmin engine
18
- bundle add lesli_admin
17
+ # Add LesliAudit engine
18
+ bundle add lesli_audit
19
19
  ```
20
20
 
21
21
  ```shell
@@ -24,20 +24,20 @@ rake lesli:db:setup
24
24
  ```
25
25
 
26
26
  ```ruby
27
- # Load LesliAdmin
27
+ # Load LesliAudit
28
28
  Rails.application.routes.draw do
29
- mount LesliAdmin::Engine => "/admin"
29
+ mount LesliAudit::Engine => "/audit"
30
30
  end
31
31
  ```
32
32
 
33
33
 
34
34
  ### Documentation
35
- * [Roadmap](./docs/roadmap.md)
35
+ * [website](https://www.lesli.dev/audit/)
36
36
  * [database](./docs/database.md)
37
37
  * [documentation](https://www.lesli.dev/documentation/)
38
38
 
39
39
 
40
- ### Get in touch
40
+ ### Get in touch with Lesli
41
41
 
42
42
  * [Website: https://www.lesli.tech](https://www.lesli.tech)
43
43
  * [Email: hello@lesli.tech](hello@lesli.tech)